| @@ -190,6 +190,9 @@ struct bpf_verifier_stack_elem { · 189 unmodified lines |
| 190 | | 190 | |
| 191 | static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx); | 191 | static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx); |
| 192 | static int release_reference(struct bpf_verifier_env *env, int ref_obj_id); | 192 | static int release_reference(struct bpf_verifier_env *env, int ref_obj_id); |
| | 193 | static void invalidate_non_owning_refs(struct bpf_verifier_env *env); |
| | 194 | static int ref_set_non_owning(struct bpf_verifier_env *env, |
| | 195 | struct bpf_reg_state *reg); |
| 193 | | 196 | |
| 194 | static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux) | 197 | static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux) |
| 195 | { | 198 | { |
| @@ -457,6 +460,11 @@ static bool type_is_ptr_alloc_obj(u32 type) · 261 unmodified lines |
| 457 | return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC; | 460 | return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC; |
| 458 | } | 461 | } |
| 459 | | 462 | |
| | 463 | static bool type_is_non_owning_ref(u32 type) |
| | 464 | { |
| | 465 | return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF; |
| | 466 | } |
| | 467 | |
| 460 | static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) | 468 | static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg) |
| 461 | { | 469 | { |
| 462 | struct btf_record *rec = NULL; | 470 | struct btf_record *rec = NULL; |
| @@ -1073,6 +1081,8 @@ static void print_verifier_state(struct bpf_verifier_env *env, · 610 unmodified lines |
| 1073 | verbose_a("id=%d", reg->id); | 1081 | verbose_a("id=%d", reg->id); |
| 1074 | if (reg->ref_obj_id) | 1082 | if (reg->ref_obj_id) |
| 1075 | verbose_a("ref_obj_id=%d", reg->ref_obj_id); | 1083 | verbose_a("ref_obj_id=%d", reg->ref_obj_id); |
| | 1084 | if (type_is_non_owning_ref(reg->type)) |
| | 1085 | verbose_a("%s", "non_own_ref"); |
| 1076 | if (t != SCALAR_VALUE) | 1086 | if (t != SCALAR_VALUE) |
| 1077 | verbose_a("off=%d", reg->off); | 1087 | verbose_a("off=%d", reg->off); |
| 1078 | if (type_is_pkt_pointer(t)) | 1088 | if (type_is_pkt_pointer(t)) |
| @@ -5052,7 +5062,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env, · 3973 unmodified lines |
| 5052 | return -EACCES; | 5062 | return -EACCES; |
| 5053 | } | 5063 | } |
| 5054 | | 5064 | |
| 5055 | if (type_is_alloc(reg->type) && !reg->ref_obj_id) { | 5065 | if (type_is_alloc(reg->type) && !type_is_non_owning_ref(reg->type) && |
| | 5066 | !reg->ref_obj_id) { |
| 5056 | verbose(env, "verifier internal error: ref_obj_id for allocated object must be non-zero\n"); | 5067 | verbose(env, "verifier internal error: ref_obj_id for allocated object must be non-zero\n"); |
| 5057 | return -EFAULT; | 5068 | return -EFAULT; |
| 5058 | } | 5069 | } |
| @@ -6042,9 +6053,7 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno, · 983 unmodified lines |
| 6042 | cur->active_lock.ptr = btf; | 6053 | cur->active_lock.ptr = btf; |
| 6043 | cur->active_lock.id = reg->id; | 6054 | cur->active_lock.id = reg->id; |
| 6044 | } else { | 6055 | } else { |
| 6045 | struct bpf_func_state *fstate = cur_func(env); | | |
| 6046 | void *ptr; | 6056 | void *ptr; |
| 6047 | int i; | | |
| 6048 | | 6057 | |
| 6049 | if (map) | 6058 | if (map) |
| 6050 | ptr = map; | 6059 | ptr = map; |
| @@ -6060,25 +6069,11 @@ static int process_spin_lock(struct bpf_verifier_env *env, int regno, · 9 unmodified lines |
| 6060 | verbose(env, "bpf_spin_unlock of different lock\n"); | 6069 | verbose(env, "bpf_spin_unlock of different lock\n"); |
| 6061 | return -EINVAL; | 6070 | return -EINVAL; |
| 6062 | } | 6071 | } |
| 6063 | cur->active_lock.ptr = NULL; | | |
| 6064 | cur->active_lock.id = 0; | | |
| 6065 | | 6072 | |
| 6066 | for (i = fstate->acquired_refs - 1; i >= 0; i--) { | 6073 | invalidate_non_owning_refs(env); |
| 6067 | int err; | | |
| 6068 | | 6074 | |
| 6069 | /* Complain on error because this reference state cannot | 6075 | cur->active_lock.ptr = NULL; |
| 6070 | * be freed before this point, as bpf_spin_lock critical | 6076 | cur->active_lock.id = 0; |
| 6071 | * section does not allow functions that release the | | |
| 6072 | * allocated object immediately. | | |
| 6073 | */ | | |
| 6074 | if (!fstate->refs[i].release_on_unlock) | | |
| 6075 | continue; | | |
| 6076 | err = release_reference(env, fstate->refs[i].id); | | |
| 6077 | if (err) { | | |
| 6078 | verbose(env, "failed to release release_on_unlock reference"); | | |
| 6079 | return err; | | |
| 6080 | } | | |
| 6081 | } | | |
| 6082 | } | 6077 | } |
| 6083 | return 0; | 6078 | return 0; |
| 6084 | } | 6079 | } |
| @@ -6546,6 +6541,23 @@ found: · 461 unmodified lines |
| 6546 | return 0; | 6541 | return 0; |
| 6547 | } | 6542 | } |
| 6548 | | 6543 | |
| | 6544 | static struct btf_field * |
| | 6545 | reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields) |
| | 6546 | { |
| | 6547 | struct btf_field *field; |
| | 6548 | struct btf_record *rec; |
| | 6549 | |
| | 6550 | rec = reg_btf_record(reg); |
| | 6551 | if (!rec) |
| | 6552 | return NULL; |
| | 6553 | |
| | 6554 | field = btf_record_find(rec, off, fields); |
| | 6555 | if (!field) |
| | 6556 | return NULL; |
| | 6557 | |
| | 6558 | return field; |
| | 6559 | } |
| | 6560 | |
| 6549 | int check_func_arg_reg_off(struct bpf_verifier_env *env, | 6561 | int check_func_arg_reg_off(struct bpf_verifier_env *env, |
| 6550 | const struct bpf_reg_state *reg, int regno, | 6562 | const struct bpf_reg_state *reg, int regno, |
| 6551 | enum bpf_arg_type arg_type) | 6563 | enum bpf_arg_type arg_type) |
| @@ -6567,6 +6579,18 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, · 15 unmodified lines |
| 6567 | */ | 6579 | */ |
| 6568 | if (arg_type_is_dynptr(arg_type) && type == PTR_TO_STACK) | 6580 | if (arg_type_is_dynptr(arg_type) && type == PTR_TO_STACK) |
| 6569 | return 0; | 6581 | return 0; |
| | 6582 | |
| | 6583 | if ((type_is_ptr_alloc_obj(type) || type_is_non_owning_ref(type)) && reg->off) { |
| | 6584 | if (reg_find_field_offset(reg, reg->off, BPF_GRAPH_NODE_OR_ROOT)) |
| | 6585 | return __check_ptr_off_reg(env, reg, regno, true); |
| | 6586 | |
| | 6587 | verbose(env, "R%d must have zero offset when passed to release func\n", |
| | 6588 | regno); |
| | 6589 | verbose(env, "No graph node or root found at R%d type:%s off:%d\n", regno, |
| | 6590 | kernel_type_name(reg->btf, reg->btf_id), reg->off); |
| | 6591 | return -EINVAL; |
| | 6592 | } |
| | 6593 | |
| 6570 | /* Doing check_ptr_off_reg check for the offset will catch this | 6594 | /* Doing check_ptr_off_reg check for the offset will catch this |
| 6571 | * because fixed_off_ok is false, but checking here allows us | 6595 | * because fixed_off_ok is false, but checking here allows us |
| 6572 | * to give the user a better error message. | 6596 | * to give the user a better error message. |
| @@ -6601,6 +6625,7 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env, · 28 unmodified lines |
| 6601 | case PTR_TO_BTF_ID | PTR_TRUSTED: | 6625 | case PTR_TO_BTF_ID | PTR_TRUSTED: |
| 6602 | case PTR_TO_BTF_ID | MEM_RCU: | 6626 | case PTR_TO_BTF_ID | MEM_RCU: |
| 6603 | case PTR_TO_BTF_ID | MEM_ALLOC | PTR_TRUSTED: | 6627 | case PTR_TO_BTF_ID | MEM_ALLOC | PTR_TRUSTED: |
| | 6628 | case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF: |
| 6604 | /* When referenced PTR_TO_BTF_ID is passed to release function, | 6629 | /* When referenced PTR_TO_BTF_ID is passed to release function, |
| 6605 | * its fixed offset must be 0. In the other cases, fixed offset | 6630 | * its fixed offset must be 0. In the other cases, fixed offset |
| 6606 | * can be non-zero. This was already checked above. So pass | 6631 | * can be non-zero. This was already checked above. So pass |
| @@ -7363,6 +7388,17 @@ static int release_reference(struct bpf_verifier_env *env, · 756 unmodified lines |
| 7363 | return 0; | 7388 | return 0; |
| 7364 | } | 7389 | } |
| 7365 | | 7390 | |
| | 7391 | static void invalidate_non_owning_refs(struct bpf_verifier_env *env) |
| | 7392 | { |
| | 7393 | struct bpf_func_state *unused; |
| | 7394 | struct bpf_reg_state *reg; |
| | 7395 | |
| | 7396 | bpf_for_each_reg_in_vstate(env->cur_state, unused, reg, ({ |
| | 7397 | if (type_is_non_owning_ref(reg->type)) |
| | 7398 | __mark_reg_unknown(env, reg); |
| | 7399 | })); |
| | 7400 | } |
| | 7401 | |
| 7366 | static void clear_caller_saved_regs(struct bpf_verifier_env *env, | 7402 | static void clear_caller_saved_regs(struct bpf_verifier_env *env, |
| 7367 | struct bpf_reg_state *regs) | 7403 | struct bpf_reg_state *regs) |
| 7368 | { | 7404 | { |
| @@ -8915,38 +8951,54 @@ static int process_kf_arg_ptr_to_kptr(struct bpf_verifier_env *env, · 1546 unmodified lines |
| 8915 | return 0; | 8951 | return 0; |
| 8916 | } | 8952 | } |
| 8917 | | 8953 | |
| 8918 | static int ref_set_release_on_unlock(struct bpf_verifier_env *env, u32 ref_obj_id) | 8954 | static int ref_set_non_owning(struct bpf_verifier_env *env, struct bpf_reg_state *reg) |
| 8919 | { | 8955 | { |
| 8920 | struct bpf_func_state *state = cur_func(env); | 8956 | struct bpf_verifier_state *state = env->cur_state; |
| | 8957 | |
| | 8958 | if (!state->active_lock.ptr) { |
| | 8959 | verbose(env, "verifier internal error: ref_set_non_owning w/o active lock\n"); |
| | 8960 | return -EFAULT; |
| | 8961 | } |
| | 8962 | |
| | 8963 | if (type_flag(reg->type) & NON_OWN_REF) { |
| | 8964 | verbose(env, "verifier internal error: NON_OWN_REF already set\n"); |
| | 8965 | return -EFAULT; |
| | 8966 | } |
| | 8967 | |
| | 8968 | reg->type |= NON_OWN_REF; |
| | 8969 | return 0; |
| | 8970 | } |
| | 8971 | |
| | 8972 | static int ref_convert_owning_non_owning(struct bpf_verifier_env *env, u32 ref_obj_id) |
| | 8973 | { |
| | 8974 | struct bpf_func_state *state, *unused; |
| 8921 | struct bpf_reg_state *reg; | 8975 | struct bpf_reg_state *reg; |
| 8922 | int i; | 8976 | int i; |
| 8923 | | 8977 | |
| 8924 | /* bpf_spin_lock only allows calling list_push and list_pop, no BPF | 8978 | state = cur_func(env); |
| 8925 | * subprogs, no global functions. This means that the references would | 8979 | |
| 8926 | * not be released inside the critical section but they may be added to | | |
| 8927 | * the reference state, and the acquired_refs are never copied out for a | | |
| 8928 | * different frame as BPF to BPF calls don't work in bpf_spin_lock | | |
| 8929 | * critical sections. | | |
| 8930 | */ | | |
| 8931 | if (!ref_obj_id) { | 8980 | if (!ref_obj_id) { |
| 8932 | verbose(env, "verifier internal error: ref_obj_id is zero for release_on_unlock\n"); | 8981 | verbose(env, "verifier internal error: ref_obj_id is zero for " |
| | 8982 | "owning -> non-owning conversion\n"); |
| 8933 | return -EFAULT; | 8983 | return -EFAULT; |
| 8934 | } | 8984 | } |
| | 8985 | |
| 8935 | for (i = 0; i < state->acquired_refs; i++) { | 8986 | for (i = 0; i < state->acquired_refs; i++) { |
| 8936 | if (state->refs[i].id == ref_obj_id) { | 8987 | if (state->refs[i].id != ref_obj_id) |
| 8937 | if (state->refs[i].release_on_unlock) { | 8988 | continue; |
| 8938 | verbose(env, "verifier internal error: expected false release_on_unlock"); | 8989 | |
| 8939 | return -EFAULT; | 8990 | /* Clear ref_obj_id here so release_reference doesn't clobber |
| | 8991 | * the whole reg |
| | 8992 | */ |
| | 8993 | bpf_for_each_reg_in_vstate(env->cur_state, unused, reg, ({ |
| | 8994 | if (reg->ref_obj_id == ref_obj_id) { |
| | 8995 | reg->ref_obj_id = 0; |
| | 8996 | ref_set_non_owning(env, reg); |
| 8940 | } | 8997 | } |
| 8941 | state->refs[i].release_on_unlock = true; | 8998 | })); |
| 8942 | /* Now mark everyone sharing same ref_obj_id as untrusted */ | 8999 | return 0; |
| 8943 | bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({ | | |
| 8944 | if (reg->ref_obj_id == ref_obj_id) | | |
| 8945 | reg->type |= PTR_UNTRUSTED; | | |
| 8946 | })); | | |
| 8947 | return 0; | | |
| 8948 | } | | |
| 8949 | } | 9000 | } |
| | 9001 | |
| 8950 | verbose(env, "verifier internal error: ref state missing for ref_obj_id\n"); | 9002 | verbose(env, "verifier internal error: ref state missing for ref_obj_id\n"); |
| 8951 | return -EFAULT; | 9003 | return -EFAULT; |
| 8952 | } | 9004 | } |
| @@ -9081,7 +9133,6 @@ static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env, · 128 unmodified lines |
| 9081 | { | 9133 | { |
| 9082 | const struct btf_type *et, *t; | 9134 | const struct btf_type *et, *t; |
| 9083 | struct btf_field *field; | 9135 | struct btf_field *field; |
| 9084 | struct btf_record *rec; | | |
| 9085 | u32 list_node_off; | 9136 | u32 list_node_off; |
| 9086 | | 9137 | |
| 9087 | if (meta->btf != btf_vmlinux || | 9138 | if (meta->btf != btf_vmlinux || |
| @@ -9098,9 +9149,8 @@ static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env, · 10 unmodified lines |
| 9098 | return -EINVAL; | 9149 | return -EINVAL; |
| 9099 | } | 9150 | } |
| 9100 | | 9151 | |
| 9101 | rec = reg_btf_record(reg); | | |
| 9102 | list_node_off = reg->off + reg->var_off.value; | 9152 | list_node_off = reg->off + reg->var_off.value; |
| 9103 | field = btf_record_find(rec, list_node_off, BPF_LIST_NODE); | 9153 | field = reg_find_field_offset(reg, list_node_off, BPF_LIST_NODE); |
| 9104 | if (!field || field->offset != list_node_off) { | 9154 | if (!field || field->offset != list_node_off) { |
| 9105 | verbose(env, "bpf_list_node not found at offset=%u\n", list_node_off); | 9155 | verbose(env, "bpf_list_node not found at offset=%u\n", list_node_off); |
| 9106 | return -EINVAL; | 9156 | return -EINVAL; |
| @@ -9126,8 +9176,8 @@ static int process_kf_arg_ptr_to_list_node(struct bpf_verifier_env *env, · 19 unmodified lines |
| 9126 | btf_name_by_offset(field->graph_root.btf, et->name_off)); | 9176 | btf_name_by_offset(field->graph_root.btf, et->name_off)); |
| 9127 | return -EINVAL; | 9177 | return -EINVAL; |
| 9128 | } | 9178 | } |
| 9129 | /* Set arg#1 for expiration after unlock */ | 9179 | |
| 9130 | return ref_set_release_on_unlock(env, reg->ref_obj_id); | 9180 | return 0; |
| 9131 | } | 9181 | } |
| 9132 | | 9182 | |
| 9133 | static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta) | 9183 | static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_arg_meta *meta) |
| @@ -9406,11 +9456,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, · 272 unmodified lines |
| 9406 | int *insn_idx_p) | 9456 | int *insn_idx_p) |
| 9407 | { | 9457 | { |
| 9408 | const struct btf_type *t, *func, *func_proto, *ptr_type; | 9458 | const struct btf_type *t, *func, *func_proto, *ptr_type; |
| | 9459 | u32 i, nargs, func_id, ptr_type_id, release_ref_obj_id; |
| 9409 | struct bpf_reg_state *regs = cur_regs(env); | 9460 | struct bpf_reg_state *regs = cur_regs(env); |
| 9410 | const char *func_name, *ptr_type_name; | 9461 | const char *func_name, *ptr_type_name; |
| 9411 | bool sleepable, rcu_lock, rcu_unlock; | 9462 | bool sleepable, rcu_lock, rcu_unlock; |
| 9412 | struct bpf_kfunc_call_arg_meta meta; | 9463 | struct bpf_kfunc_call_arg_meta meta; |
| 9413 | u32 i, nargs, func_id, ptr_type_id; | | |
| 9414 | int err, insn_idx = *insn_idx_p; | 9464 | int err, insn_idx = *insn_idx_p; |
| 9415 | const struct btf_param *args; | 9465 | const struct btf_param *args; |
| 9416 | const struct btf_type *ret_t; | 9466 | const struct btf_type *ret_t; |
| @@ -9505,6 +9555,24 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn, · 88 unmodified lines |
| 9505 | } | 9555 | } |
| 9506 | } | 9556 | } |
| 9507 | | 9557 | |
| | 9558 | if (meta.func_id == special_kfunc_list[KF_bpf_list_push_front] || |
| | 9559 | meta.func_id == special_kfunc_list[KF_bpf_list_push_back]) { |
| | 9560 | release_ref_obj_id = regs[BPF_REG_2].ref_obj_id; |
| | 9561 | err = ref_convert_owning_non_owning(env, release_ref_obj_id); |
| | 9562 | if (err) { |
| | 9563 | verbose(env, "kfunc %s#%d conversion of owning ref to non-owning failed\n", |
| | 9564 | func_name, func_id); |
| | 9565 | return err; |
| | 9566 | } |
| | 9567 | |
| | 9568 | err = release_reference(env, release_ref_obj_id); |
| | 9569 | if (err) { |
| | 9570 | verbose(env, "kfunc %s#%d reference has not been acquired before\n", |
| | 9571 | func_name, func_id); |
| | 9572 | return err; |
| | 9573 | } |
| | 9574 | } |
| | 9575 | |
| 9508 | for (i = 0; i < CALLER_SAVED_REGS; i++) | 9576 | for (i = 0; i < CALLER_SAVED_REGS; i++) |
| 9509 | mark_reg_not_init(env, regs, caller_saved[i]); | 9577 | mark_reg_not_init(env, regs, caller_saved[i]); |
| 9510 | | 9578 | |
| @@ -11825,8 +11893,10 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state, · 2314 unmodified lines |
| 11825 | */ | 11893 | */ |
| 11826 | if (WARN_ON_ONCE(reg->smin_value || reg->smax_value || !tnum_equals_const(reg->var_off, 0))) | 11894 | if (WARN_ON_ONCE(reg->smin_value || reg->smax_value || !tnum_equals_const(reg->var_off, 0))) |
| 11827 | return; | 11895 | return; |
| 11828 | if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC | PTR_MAYBE_NULL) && WARN_ON_ONCE(reg->off)) | 11896 | if (!(type_is_ptr_alloc_obj(reg->type) || type_is_non_owning_ref(reg->type)) && |
| | 11897 | WARN_ON_ONCE(reg->off)) |
| 11829 | return; | 11898 | return; |
| | 11899 | |
| 11830 | if (is_null) { | 11900 | if (is_null) { |
| 11831 | reg->type = SCALAR_VALUE; | 11901 | reg->type = SCALAR_VALUE; |
| 11832 | /* We don't need id and ref_obj_id from this point | 11902 | /* We don't need id and ref_obj_id from this point |