@@ -196,7 +196,8 @@ struct bpf_verifier_stack_elem {
196196
197197#define BPF_PRIV_STACK_MIN_SIZE 64
198198
199- static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx);
199+ static int acquire_reference(struct bpf_verifier_env *env, int insn_idx);
200+ static int release_reference_nomark(struct bpf_verifier_state *state, int ref_obj_id);
200201static int release_reference(struct bpf_verifier_env *env, int ref_obj_id);
201202static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
202203static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env);
@@ -752,7 +753,7 @@ static int mark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_
752753 if (clone_ref_obj_id)
753754 id = clone_ref_obj_id;
754755 else
755- id = acquire_reference_state (env, insn_idx);
756+ id = acquire_reference (env, insn_idx);
756757
757758 if (id < 0)
758759 return id;
@@ -1014,7 +1015,7 @@ static int mark_stack_slots_iter(struct bpf_verifier_env *env,
10141015 if (spi < 0)
10151016 return spi;
10161017
1017- id = acquire_reference_state (env, insn_idx);
1018+ id = acquire_reference (env, insn_idx);
10181019 if (id < 0)
10191020 return id;
10201021
@@ -1333,77 +1334,68 @@ static int grow_stack_state(struct bpf_verifier_env *env, struct bpf_func_state
13331334 * On success, returns a valid pointer id to associate with the register
13341335 * On failure, returns a negative errno.
13351336 */
1336- static int acquire_reference_state(struct bpf_verifier_env *env, int insn_idx)
1337+ static struct bpf_reference_state * acquire_reference_state(struct bpf_verifier_env *env, int insn_idx)
13371338{
13381339 struct bpf_verifier_state *state = env->cur_state;
13391340 int new_ofs = state->acquired_refs;
1340- int id, err;
1341+ int err;
13411342
13421343 err = resize_reference_state(state, state->acquired_refs + 1);
13431344 if (err)
1344- return err;
1345- id = ++env->id_gen;
1346- state->refs[new_ofs].type = REF_TYPE_PTR;
1347- state->refs[new_ofs].id = id;
1345+ return NULL;
13481346 state->refs[new_ofs].insn_idx = insn_idx;
13491347
1350- return id;
1348+ return &state->refs[new_ofs];
1349+ }
1350+
1351+ static int acquire_reference(struct bpf_verifier_env *env, int insn_idx)
1352+ {
1353+ struct bpf_reference_state *s;
1354+
1355+ s = acquire_reference_state(env, insn_idx);
1356+ if (!s)
1357+ return -ENOMEM;
1358+ s->type = REF_TYPE_PTR;
1359+ s->id = ++env->id_gen;
1360+ return s->id;
13511361}
13521362
13531363static int acquire_lock_state(struct bpf_verifier_env *env, int insn_idx, enum ref_state_type type,
13541364 int id, void *ptr)
13551365{
13561366 struct bpf_verifier_state *state = env->cur_state;
1357- int new_ofs = state->acquired_refs;
1358- int err;
1367+ struct bpf_reference_state *s;
13591368
1360- err = resize_reference_state(state, state->acquired_refs + 1);
1361- if (err)
1362- return err;
1363- state->refs[new_ofs].type = type;
1364- state->refs[new_ofs].id = id;
1365- state->refs[new_ofs].insn_idx = insn_idx;
1366- state->refs[new_ofs].ptr = ptr;
1369+ s = acquire_reference_state(env, insn_idx);
1370+ s->type = type;
1371+ s->id = id;
1372+ s->ptr = ptr;
13671373
13681374 state->active_locks++;
13691375 return 0;
13701376}
13711377
1372- /* release function corresponding to acquire_reference_state(). Idempotent. */
1373- static int release_reference_state(struct bpf_verifier_state *state, int ptr_id)
1378+ static void release_reference_state(struct bpf_verifier_state *state, int idx)
13741379{
1375- int i, last_idx;
1380+ int last_idx;
13761381
13771382 last_idx = state->acquired_refs - 1;
1378- for (i = 0; i < state->acquired_refs; i++) {
1379- if (state->refs[i].type != REF_TYPE_PTR)
1380- continue;
1381- if (state->refs[i].id == ptr_id) {
1382- if (last_idx && i != last_idx)
1383- memcpy(&state->refs[i], &state->refs[last_idx],
1384- sizeof(*state->refs));
1385- memset(&state->refs[last_idx], 0, sizeof(*state->refs));
1386- state->acquired_refs--;
1387- return 0;
1388- }
1389- }
1390- return -EINVAL;
1383+ if (last_idx && idx != last_idx)
1384+ memcpy(&state->refs[idx], &state->refs[last_idx], sizeof(*state->refs));
1385+ memset(&state->refs[last_idx], 0, sizeof(*state->refs));
1386+ state->acquired_refs--;
1387+ return;
13911388}
13921389
13931390static int release_lock_state(struct bpf_verifier_state *state, int type, int id, void *ptr)
13941391{
1395- int i, last_idx ;
1392+ int i;
13961393
1397- last_idx = state->acquired_refs - 1;
13981394 for (i = 0; i < state->acquired_refs; i++) {
13991395 if (state->refs[i].type != type)
14001396 continue;
14011397 if (state->refs[i].id == id && state->refs[i].ptr == ptr) {
1402- if (last_idx && i != last_idx)
1403- memcpy(&state->refs[i], &state->refs[last_idx],
1404- sizeof(*state->refs));
1405- memset(&state->refs[last_idx], 0, sizeof(*state->refs));
1406- state->acquired_refs--;
1398+ release_reference_state(state, i);
14071399 state->active_locks--;
14081400 return 0;
14091401 }
@@ -9655,21 +9647,38 @@ static void mark_pkt_end(struct bpf_verifier_state *vstate, int regn, bool range
96559647 reg->range = AT_PKT_END;
96569648}
96579649
9650+ static int release_reference_nomark(struct bpf_verifier_state *state, int ref_obj_id)
9651+ {
9652+ int i;
9653+
9654+ for (i = 0; i < state->acquired_refs; i++) {
9655+ if (state->refs[i].type != REF_TYPE_PTR)
9656+ continue;
9657+ if (state->refs[i].id == ref_obj_id) {
9658+ release_reference_state(state, i);
9659+ return 0;
9660+ }
9661+ }
9662+ return -EINVAL;
9663+ }
9664+
96589665/* The pointer with the specified id has released its reference to kernel
96599666 * resources. Identify all copies of the same pointer and clear the reference.
9667+ *
9668+ * This is the release function corresponding to acquire_reference(). Idempotent.
96609669 */
9661- static int release_reference(struct bpf_verifier_env *env,
9662- int ref_obj_id)
9670+ static int release_reference(struct bpf_verifier_env *env, int ref_obj_id)
96639671{
9672+ struct bpf_verifier_state *vstate = env->cur_state;
96649673 struct bpf_func_state *state;
96659674 struct bpf_reg_state *reg;
96669675 int err;
96679676
9668- err = release_reference_state(env->cur_state , ref_obj_id);
9677+ err = release_reference_nomark(vstate , ref_obj_id);
96699678 if (err)
96709679 return err;
96719680
9672- bpf_for_each_reg_in_vstate(env->cur_state , state, reg, ({
9681+ bpf_for_each_reg_in_vstate(vstate , state, reg, ({
96739682 if (reg->ref_obj_id == ref_obj_id)
96749683 mark_reg_invalid(env, reg);
96759684 }));
@@ -10762,7 +10771,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
1076210771 struct bpf_func_state *state;
1076310772 struct bpf_reg_state *reg;
1076410773
10765- err = release_reference_state (env->cur_state, ref_obj_id);
10774+ err = release_reference_nomark (env->cur_state, ref_obj_id);
1076610775 if (!err) {
1076710776 bpf_for_each_reg_in_vstate(env->cur_state, state, reg, ({
1076810777 if (reg->ref_obj_id == ref_obj_id) {
@@ -11095,7 +11104,7 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn
1109511104 /* For release_reference() */
1109611105 regs[BPF_REG_0].ref_obj_id = meta.ref_obj_id;
1109711106 } else if (is_acquire_function(func_id, meta.map_ptr)) {
11098- int id = acquire_reference_state (env, insn_idx);
11107+ int id = acquire_reference (env, insn_idx);
1109911108
1110011109 if (id < 0)
1110111110 return id;
@@ -13058,7 +13067,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1305813067 }
1305913068 mark_btf_func_reg_size(env, BPF_REG_0, sizeof(void *));
1306013069 if (is_kfunc_acquire(&meta)) {
13061- int id = acquire_reference_state (env, insn_idx);
13070+ int id = acquire_reference (env, insn_idx);
1306213071
1306313072 if (id < 0)
1306413073 return id;
@@ -15354,7 +15363,7 @@ static void mark_ptr_or_null_regs(struct bpf_verifier_state *vstate, u32 regno,
1535415363 * No one could have freed the reference state before
1535515364 * doing the NULL check.
1535615365 */
15357- WARN_ON_ONCE(release_reference_state (vstate, id));
15366+ WARN_ON_ONCE(release_reference_nomark (vstate, id));
1535815367
1535915368 bpf_for_each_reg_in_vstate(vstate, state, reg, ({
1536015369 mark_ptr_or_null_reg(state, reg, id, is_null);
0 commit comments