@@ -8225,17 +8225,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
82258225 return err;
82268226
82278227skip_type_check:
8228- if (arg_type_is_release(arg_type)) {
8229- if (!arg_type_is_dynptr(arg_type) && !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
8230- verbose(env, "R%d must be referenced when passed to release function\n",
8231- regno);
8232- return -EINVAL;
8233- }
8234- if (meta->release_regno) {
8235- verifier_bug(env, "more than one release argument");
8236- return -EFAULT;
8237- }
8238- meta->release_regno = regno;
8228+ if (arg_type_is_release(arg_type) && !arg_type_is_dynptr(arg_type) &&
8229+ !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
8230+ verbose(env, "release helper %s expects referenced PTR_TO_BTF_ID passed to %s\n",
8231+ func_id_name(meta->func_id), reg_arg_name(env, argno));
8232+ return -EINVAL;
82398233 }
82408234
82418235 if (reg_is_referenced(env, reg))
@@ -8798,11 +8792,29 @@ static bool check_mem_arg_rw_flag_ok(const struct bpf_func_proto *fn)
87988792 return true;
87998793}
88008794
8801- static int check_func_proto(const struct bpf_func_proto *fn)
8795+ static bool check_proto_release_reg(const struct bpf_func_proto *fn, struct bpf_call_arg_meta *meta)
8796+ {
8797+ int i;
8798+
8799+ for (i = 0; i < ARRAY_SIZE(fn->arg_type); i++) {
8800+ enum bpf_arg_type arg_type = fn->arg_type[i];
8801+
8802+ if (arg_type_is_release(arg_type)) {
8803+ if (meta->release_regno)
8804+ return false;
8805+ meta->release_regno = i + 1;
8806+ }
8807+ }
8808+
8809+ return true;
8810+ }
8811+
8812+ static int check_func_proto(const struct bpf_func_proto *fn, struct bpf_call_arg_meta *meta)
88028813{
88038814 return check_raw_mode_ok(fn) &&
88048815 check_arg_pair_ok(fn) &&
88058816 check_mem_arg_rw_flag_ok(fn) &&
8817+ check_proto_release_reg(fn, meta) &&
88068818 check_btf_id_ok(fn) ? 0 : -EINVAL;
88078819}
88088820
@@ -8956,6 +8968,42 @@ static void invalidate_non_owning_refs(struct bpf_verifier_env *env)
89568968 }));
89578969}
89588970
8971+ static void invalidate_rcu_protected_refs(struct bpf_verifier_env *env)
8972+ {
8973+ struct bpf_stack_state *stack;
8974+ struct bpf_func_state *state;
8975+ struct bpf_reg_state *reg;
8976+ u32 clear_mask = (1 << STACK_SPILL) | (1 << STACK_ITER);
8977+
8978+ bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg, stack, clear_mask, ({
8979+ if (reg->type & MEM_RCU) {
8980+ reg->type &= ~(MEM_RCU | PTR_MAYBE_NULL);
8981+ reg->type |= PTR_UNTRUSTED;
8982+ }
8983+ }));
8984+ }
8985+
8986+ static int ref_convert_alloc_rcu_protected(struct bpf_verifier_env *env, u32 id)
8987+ {
8988+ struct bpf_func_state *state;
8989+ struct bpf_reg_state *reg;
8990+ int err;
8991+
8992+ err = release_reference_nomark(env->cur_state, id);
8993+
8994+ bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
8995+ if (reg->id != id)
8996+ continue;
8997+ if ((reg->type & MEM_ALLOC) && (reg->type & MEM_PERCPU)) {
8998+ reg->id = 0;
8999+ reg->type &= ~MEM_ALLOC;
9000+ reg->type |= MEM_RCU;
9001+ }
9002+ }));
9003+
9004+ return err;
9005+ }
9006+
89599007static void clear_caller_saved_regs(struct bpf_verifier_env *env,
89609008 struct bpf_reg_state *regs)
89619009{
@@ -10028,6 +10076,24 @@ static const char *non_sleepable_context_description(struct bpf_verifier_env *en
1002810076 return "non-sleepable prog";
1002910077}
1003010078
10079+ static int release_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
10080+ bool convert_rcu, bool release_dynptr)
10081+ {
10082+ int err = -EINVAL;
10083+
10084+ if (bpf_register_is_null(reg))
10085+ return 0;
10086+
10087+ if (release_dynptr)
10088+ err = unmark_stack_slots_dynptr(env, reg);
10089+ else if (convert_rcu)
10090+ err = ref_convert_alloc_rcu_protected(env, reg->id);
10091+ else if (reg_is_referenced(env, reg))
10092+ err = release_reference(env, reg->id);
10093+
10094+ return err;
10095+ }
10096+
1003110097static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1003210098 int *insn_idx_p)
1003310099{
@@ -10077,7 +10143,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
1007710143 memset(&meta, 0, sizeof(meta));
1007810144 meta.pkt_access = fn->pkt_access;
1007910145
10080- err = check_func_proto(fn);
10146+ err = check_func_proto(fn, &meta );
1008110147 if (err) {
1008210148 verifier_bug(env, "incorrect func proto %s#%d", func_id_name(func_id), func_id);
1008310149 return err;
@@ -10122,37 +10188,11 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
1012210188 }
1012310189
1012410190 if (meta.release_regno) {
10125- err = -EINVAL;
10126- if (arg_type_is_dynptr(fn->arg_type[meta.release_regno - BPF_REG_1])) {
10127- err = unmark_stack_slots_dynptr(env, ®s[meta.release_regno]);
10128- } else if (func_id == BPF_FUNC_kptr_xchg && meta.ref_obj.id) {
10129- u32 id = meta.ref_obj.id;
10130- bool in_rcu = in_rcu_cs(env);
10131- struct bpf_func_state *state;
10132- struct bpf_reg_state *reg;
10133-
10134- err = release_reference_nomark(env->cur_state, id);
10135- if (!err) {
10136- bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
10137- if (reg->id == id) {
10138- if (in_rcu && (reg->type & MEM_ALLOC) && (reg->type & MEM_PERCPU)) {
10139- reg->id = 0;
10140- reg->type &= ~MEM_ALLOC;
10141- reg->type |= MEM_RCU;
10142- } else {
10143- mark_reg_invalid(env, reg);
10144- }
10145- }
10146- }));
10147- }
10148- } else if (meta.ref_obj.id) {
10149- err = release_reference(env, meta.ref_obj.id);
10150- } else if (bpf_register_is_null(®s[meta.release_regno])) {
10151- /* meta.ref_obj.id can only be 0 if register that is meant to be
10152- * released is NULL, which must be > R0.
10153- */
10154- err = 0;
10155- }
10191+ struct bpf_reg_state *reg = ®s[meta.release_regno];
10192+ bool convert_rcu = (func_id == BPF_FUNC_kptr_xchg) && in_rcu_cs(env) &&
10193+ (reg->type & MEM_ALLOC) && (reg->type & MEM_PERCPU);
10194+
10195+ err = release_reg(env, reg, convert_rcu, !!meta.dynptr.id);
1015610196 if (err)
1015710197 return err;
1015810198 }
@@ -10547,7 +10587,6 @@ static bool is_kfunc_release(struct bpf_kfunc_call_arg_meta *meta)
1054710587 return meta->kfunc_flags & KF_RELEASE;
1054810588}
1054910589
10550-
1055110590static bool is_kfunc_destructive(struct bpf_kfunc_call_arg_meta *meta)
1055210591{
1055310592 return meta->kfunc_flags & KF_DESTRUCTIVE;
@@ -11912,24 +11951,16 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1191211951 return -EACCES;
1191311952 }
1191411953
11915- if (reg_is_referenced(env, reg)) {
11916- if (is_kfunc_release(meta) && meta->ref_obj.cnt) {
11917- verbose(env, "more than one arg with referenced id %s %u %u",
11918- reg_arg_name(env, argno), reg->id,
11919- meta->ref_obj.id);
11920- return -EFAULT;
11921- }
11922- update_ref_obj(&meta->ref_obj, reg);
11923- if (is_kfunc_release(meta)) {
11924- if (regno < 0) {
11925- verbose(env, "%s release arg cannot be a stack argument\n",
11926- reg_arg_name(env, argno));
11927- return -EINVAL;
11928- }
11929- meta->release_regno = regno;
11930- }
11954+ if (regno == meta->release_regno && !is_kfunc_arg_dynptr(meta->btf, &args[i]) &&
11955+ !reg_is_referenced(env, reg) && !bpf_register_is_null(reg)) {
11956+ verbose(env, "release kfunc %s expects referenced PTR_TO_BTF_ID passed to %s\n",
11957+ func_name, reg_arg_name(env, argno));
11958+ return -EINVAL;
1193111959 }
1193211960
11961+ if (reg_is_referenced(env, reg))
11962+ update_ref_obj(&meta->ref_obj, reg);
11963+
1193311964 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
1193411965 ref_tname = btf_name_by_offset(btf, ref_t->name_off);
1193511966
@@ -11993,7 +12024,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1199312024 }
1199412025 }
1199512026 fallthrough;
11996- case KF_ARG_PTR_TO_DYNPTR:
1199712027 case KF_ARG_PTR_TO_ITER:
1199812028 case KF_ARG_PTR_TO_LIST_HEAD:
1199912029 case KF_ARG_PTR_TO_LIST_NODE:
@@ -12010,6 +12040,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1201012040 case KF_ARG_PTR_TO_IRQ_FLAG:
1201112041 case KF_ARG_PTR_TO_RES_SPIN_LOCK:
1201212042 break;
12043+ case KF_ARG_PTR_TO_DYNPTR:
12044+ arg_type = ARG_PTR_TO_DYNPTR;
12045+ break;
1201312046 case KF_ARG_PTR_TO_CTX:
1201412047 arg_type = ARG_PTR_TO_CTX;
1201512048 break;
@@ -12018,7 +12051,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1201812051 return -EFAULT;
1201912052 }
1202012053
12021- if (is_kfunc_release(meta) && reg_is_referenced(env, reg) )
12054+ if (regno == meta->release_regno )
1202212055 arg_type |= OBJ_RELEASE;
1202312056 ret = check_func_arg_reg_off(env, reg, argno, arg_type);
1202412057 if (ret < 0)
@@ -12083,12 +12116,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1208312116 dynptr_arg_type |= DYNPTR_TYPE_FILE;
1208412117 } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_file_discard]) {
1208512118 dynptr_arg_type |= DYNPTR_TYPE_FILE | OBJ_RELEASE;
12086- if (regno < 0) {
12087- verbose(env, "%s release arg cannot be a stack argument\n",
12088- reg_arg_name(env, argno));
12089- return -EINVAL;
12090- }
12091- meta->release_regno = regno;
1209212119 } else if (meta->func_id == special_kfunc_list[KF_bpf_dynptr_clone] &&
1209312120 (dynptr_arg_type & MEM_UNINIT)) {
1209412121 enum bpf_dynptr_type parent_type = meta->dynptr.type;
@@ -12377,12 +12404,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1237712404 }
1237812405 }
1237912406
12380- if (is_kfunc_release(meta) && !meta->release_regno) {
12381- verbose(env, "release kernel function %s expects refcounted PTR_TO_BTF_ID\n",
12382- func_name);
12383- return -EINVAL;
12384- }
12385-
1238612407 return 0;
1238712408}
1238812409
@@ -12409,6 +12430,10 @@ int bpf_fetch_kfunc_arg_meta(struct bpf_verifier_env *env,
1240912430
1241012431 meta->kfunc_flags = *kfunc.flags;
1241112432
12433+ /* Only support release referenced argument passed by register */
12434+ if (is_kfunc_release(meta))
12435+ meta->release_regno = BPF_REG_1;
12436+
1241212437 return 0;
1241312438}
1241412439
@@ -12899,23 +12924,12 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1289912924 if (rcu_lock) {
1290012925 env->cur_state->active_rcu_locks++;
1290112926 } else if (rcu_unlock) {
12902- struct bpf_stack_state *stack;
12903- struct bpf_func_state *state;
12904- struct bpf_reg_state *reg;
12905- u32 clear_mask = (1 << STACK_SPILL) | (1 << STACK_ITER);
12906-
1290712927 if (env->cur_state->active_rcu_locks == 0) {
1290812928 verbose(env, "unmatched rcu read unlock (kernel function %s)\n", func_name);
1290912929 return -EINVAL;
1291012930 }
12911- if (--env->cur_state->active_rcu_locks == 0) {
12912- bpf_for_each_reg_in_vstate_mask(env->cur_state, state, reg, stack, clear_mask, ({
12913- if (reg->type & MEM_RCU) {
12914- reg->type &= ~(MEM_RCU | PTR_MAYBE_NULL);
12915- reg->type |= PTR_UNTRUSTED;
12916- }
12917- }));
12918- }
12931+ if (--env->cur_state->active_rcu_locks == 0)
12932+ invalidate_rcu_protected_refs(env);
1291912933 } else if (preempt_disable) {
1292012934 env->cur_state->active_preempt_locks++;
1292112935 } else if (preempt_enable) {
@@ -12946,13 +12960,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1294612960 * PTR_TO_BTF_ID in bpf_kfunc_arg_meta, do the release now.
1294712961 */
1294812962 if (meta.release_regno) {
12949- struct bpf_reg_state *reg = ®s[meta.release_regno];
12950-
12951- if (meta.dynptr.id) {
12952- err = unmark_stack_slots_dynptr(env, reg);
12953- } else {
12954- err = release_reference(env, reg->id);
12955- }
12963+ err = release_reg(env, ®s[meta.release_regno], false, !!meta.dynptr.id);
1295612964 if (err)
1295712965 return err;
1295812966 }
0 commit comments