Skip to content

Commit 079313e

Browse files
bpf: Refactor {acquire,release}_reference_state
JIRA: https://issues.redhat.com/browse/RHEL-78201 commit 769b0f1 Author: Kumar Kartikeya Dwivedi <memxor@gmail.com> Date: Tue Dec 3 19:03:55 2024 -0800 bpf: Refactor {acquire,release}_reference_state In preparation for introducing support for more reference types which have to add and remove reference state, refactor the acquire_reference_state and release_reference_state functions to share common logic. The acquire_reference_state function simply handles growing the acquired refs and returning the pointer to the new uninitialized element, which can be filled in by the caller. The release_reference_state function simply erases a reference state entry in the acquired_refs array and shrinks it. The callers are responsible for finding the suitable element by matching on various fields of the reference state and requesting deletion through this function. It is not supposed to be called directly. Existing callers of release_reference_state were using it to find and remove state for a given ref_obj_id without scrubbing the associated registers in the verifier state. Introduce release_reference_nomark to provide this functionality and convert callers. We now use this new release_reference_nomark function within release_reference as well. It needs to operate on a verifier state instead of taking verifier env as mark_ptr_or_null_regs requires operating on verifier state of the two branches of a NULL condition check, therefore env->cur_state cannot be used directly. Acked-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20241204030400.208005-3-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
1 parent e9ded77 commit 079313e

File tree

1 file changed

+59
-50
lines changed

1 file changed

+59
-50
lines changed

kernel/bpf/verifier.c

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
200201
static int release_reference(struct bpf_verifier_env *env, int ref_obj_id);
201202
static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
202203
static 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

13531363
static 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

13931390
static 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

Comments
 (0)