Skip to content

Commit 5564ee3

Browse files
eddyz87Alexei Starovoitov
authored andcommitted
bpf: use list_head to track explored states and free list
The next patch in the set needs the ability to remove individual states from env->free_list while only holding a pointer to the state. Which requires env->free_list to be a doubly linked list. This patch converts env->free_list and struct bpf_verifier_state_list to use struct list_head for this purpose. The change to env->explored_states is collateral. Signed-off-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 590eee4 commit 5564ee3

File tree

2 files changed

+42
-41
lines changed

2 files changed

+42
-41
lines changed

include/linux/bpf_verifier.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ struct bpf_verifier_state {
498498
/* linked list of verifier states used to prune search */
499499
struct bpf_verifier_state_list {
500500
struct bpf_verifier_state state;
501-
struct bpf_verifier_state_list *next;
501+
struct list_head node;
502502
int miss_cnt, hit_cnt;
503503
};
504504

@@ -710,8 +710,11 @@ struct bpf_verifier_env {
710710
bool test_state_freq; /* test verifier with different pruning frequency */
711711
bool test_reg_invariants; /* fail verification on register invariants violations */
712712
struct bpf_verifier_state *cur_state; /* current verifier state */
713-
struct bpf_verifier_state_list **explored_states; /* search pruning optimization */
714-
struct bpf_verifier_state_list *free_list;
713+
/* Search pruning optimization, array of list_heads for
714+
* lists of struct bpf_verifier_state_list.
715+
*/
716+
struct list_head *explored_states;
717+
struct list_head free_list; /* list of struct bpf_verifier_state_list */
715718
struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
716719
struct btf_mod_pair used_btfs[MAX_USED_BTFS]; /* array of BTF's used by BPF program */
717720
u32 used_map_cnt; /* number of used maps */

kernel/bpf/verifier.c

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,7 +1691,7 @@ static u32 state_htab_size(struct bpf_verifier_env *env)
16911691
return env->prog->len;
16921692
}
16931693

1694-
static struct bpf_verifier_state_list **explored_state(struct bpf_verifier_env *env, int idx)
1694+
static struct list_head *explored_state(struct bpf_verifier_env *env, int idx)
16951695
{
16961696
struct bpf_verifier_state *cur = env->cur_state;
16971697
struct bpf_func_state *state = cur->frame[cur->curframe];
@@ -8443,10 +8443,12 @@ static struct bpf_verifier_state *find_prev_entry(struct bpf_verifier_env *env,
84438443
{
84448444
struct bpf_verifier_state_list *sl;
84458445
struct bpf_verifier_state *st;
8446+
struct list_head *pos, *head;
84468447

84478448
/* Explored states are pushed in stack order, most recent states come first */
8448-
sl = *explored_state(env, insn_idx);
8449-
for (; sl; sl = sl->next) {
8449+
head = explored_state(env, insn_idx);
8450+
list_for_each(pos, head) {
8451+
sl = container_of(pos, struct bpf_verifier_state_list, node);
84508452
/* If st->branches != 0 state is a part of current DFS verification path,
84518453
* hence cur & st for a loop.
84528454
*/
@@ -17857,20 +17859,20 @@ static void clean_live_states(struct bpf_verifier_env *env, int insn,
1785717859
{
1785817860
struct bpf_verifier_state *loop_entry;
1785917861
struct bpf_verifier_state_list *sl;
17862+
struct list_head *pos, *head;
1786017863

17861-
sl = *explored_state(env, insn);
17862-
while (sl) {
17864+
head = explored_state(env, insn);
17865+
list_for_each(pos, head) {
17866+
sl = container_of(pos, struct bpf_verifier_state_list, node);
1786317867
if (sl->state.branches)
17864-
goto next;
17868+
continue;
1786517869
loop_entry = get_loop_entry(env, &sl->state);
1786617870
if (!IS_ERR_OR_NULL(loop_entry) && loop_entry->branches)
17867-
goto next;
17871+
continue;
1786817872
if (sl->state.insn_idx != insn ||
1786917873
!same_callsites(&sl->state, cur))
17870-
goto next;
17874+
continue;
1787117875
clean_verifier_state(env, &sl->state);
17872-
next:
17873-
sl = sl->next;
1787417876
}
1787517877
}
1787617878

@@ -18561,10 +18563,11 @@ static bool iter_active_depths_differ(struct bpf_verifier_state *old, struct bpf
1856118563
static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
1856218564
{
1856318565
struct bpf_verifier_state_list *new_sl;
18564-
struct bpf_verifier_state_list *sl, **pprev;
18566+
struct bpf_verifier_state_list *sl;
1856518567
struct bpf_verifier_state *cur = env->cur_state, *new, *loop_entry;
1856618568
int i, j, n, err, states_cnt = 0;
1856718569
bool force_new_state, add_new_state, force_exact;
18570+
struct list_head *pos, *tmp, *head;
1856818571

1856918572
force_new_state = env->test_state_freq || is_force_checkpoint(env, insn_idx) ||
1857018573
/* Avoid accumulating infinitely long jmp history */
@@ -18583,15 +18586,14 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
1858318586
env->insn_processed - env->prev_insn_processed >= 8)
1858418587
add_new_state = true;
1858518588

18586-
pprev = explored_state(env, insn_idx);
18587-
sl = *pprev;
18588-
1858918589
clean_live_states(env, insn_idx, cur);
1859018590

18591-
while (sl) {
18591+
head = explored_state(env, insn_idx);
18592+
list_for_each_safe(pos, tmp, head) {
18593+
sl = container_of(pos, struct bpf_verifier_state_list, node);
1859218594
states_cnt++;
1859318595
if (sl->state.insn_idx != insn_idx)
18594-
goto next;
18596+
continue;
1859518597

1859618598
if (sl->state.branches) {
1859718599
struct bpf_func_state *frame = sl->state.frame[sl->state.curframe];
@@ -18796,7 +18798,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
1879618798
/* the state is unlikely to be useful. Remove it to
1879718799
* speed up verification
1879818800
*/
18799-
*pprev = sl->next;
18801+
list_del(&sl->node);
1880018802
if (sl->state.frame[0]->regs[0].live & REG_LIVE_DONE &&
1880118803
!sl->state.used_as_loop_entry) {
1880218804
u32 br = sl->state.branches;
@@ -18812,15 +18814,9 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
1881218814
* walk it later. Add it for free_list instead to
1881318815
* be freed at the end of verification
1881418816
*/
18815-
sl->next = env->free_list;
18816-
env->free_list = sl;
18817+
list_add(&sl->node, &env->free_list);
1881718818
}
18818-
sl = *pprev;
18819-
continue;
1882018819
}
18821-
next:
18822-
pprev = &sl->next;
18823-
sl = *pprev;
1882418820
}
1882518821

1882618822
if (env->max_states_per_insn < states_cnt)
@@ -18869,8 +18865,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
1886918865
cur->first_insn_idx = insn_idx;
1887018866
cur->insn_hist_start = cur->insn_hist_end;
1887118867
cur->dfs_depth = new->dfs_depth + 1;
18872-
new_sl->next = *explored_state(env, insn_idx);
18873-
*explored_state(env, insn_idx) = new_sl;
18868+
list_add(&new_sl->node, head);
18869+
1887418870
/* connect new state to parentage chain. Current frame needs all
1887518871
* registers connected. Only r6 - r9 of the callers are alive (pushed
1887618872
* to the stack implicitly by JITs) so in callers' frames connect just
@@ -22194,31 +22190,29 @@ static int remove_fastcall_spills_fills(struct bpf_verifier_env *env)
2219422190

2219522191
static void free_states(struct bpf_verifier_env *env)
2219622192
{
22197-
struct bpf_verifier_state_list *sl, *sln;
22193+
struct bpf_verifier_state_list *sl;
22194+
struct list_head *head, *pos, *tmp;
2219822195
int i;
2219922196

22200-
sl = env->free_list;
22201-
while (sl) {
22202-
sln = sl->next;
22197+
list_for_each_safe(pos, tmp, &env->free_list) {
22198+
sl = container_of(pos, struct bpf_verifier_state_list, node);
2220322199
free_verifier_state(&sl->state, false);
2220422200
kfree(sl);
22205-
sl = sln;
2220622201
}
22207-
env->free_list = NULL;
22202+
INIT_LIST_HEAD(&env->free_list);
2220822203

2220922204
if (!env->explored_states)
2221022205
return;
2221122206

2221222207
for (i = 0; i < state_htab_size(env); i++) {
22213-
sl = env->explored_states[i];
22208+
head = &env->explored_states[i];
2221422209

22215-
while (sl) {
22216-
sln = sl->next;
22210+
list_for_each_safe(pos, tmp, head) {
22211+
sl = container_of(pos, struct bpf_verifier_state_list, node);
2221722212
free_verifier_state(&sl->state, false);
2221822213
kfree(sl);
22219-
sl = sln;
2222022214
}
22221-
env->explored_states[i] = NULL;
22215+
INIT_LIST_HEAD(&env->explored_states[i]);
2222222216
}
2222322217
}
2222422218

@@ -23186,12 +23180,16 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
2318623180
env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS;
2318723181

2318823182
env->explored_states = kvcalloc(state_htab_size(env),
23189-
sizeof(struct bpf_verifier_state_list *),
23183+
sizeof(struct list_head),
2319023184
GFP_USER);
2319123185
ret = -ENOMEM;
2319223186
if (!env->explored_states)
2319323187
goto skip_full_check;
2319423188

23189+
for (i = 0; i < state_htab_size(env); i++)
23190+
INIT_LIST_HEAD(&env->explored_states[i]);
23191+
INIT_LIST_HEAD(&env->free_list);
23192+
2319523193
ret = check_btf_info_early(env, attr, uattr);
2319623194
if (ret < 0)
2319723195
goto skip_full_check;

0 commit comments

Comments
 (0)