@@ -5436,7 +5436,25 @@ enum {
54365436 BRANCH = 2 ,
54375437};
54385438
5439- #define STATE_LIST_MARK ((struct bpf_verifier_state_list *) -1L)
5439+ static u32 state_htab_size (struct bpf_verifier_env * env )
5440+ {
5441+ return env -> prog -> len ;
5442+ }
5443+
5444+ static struct bpf_verifier_state_list * * explored_state (
5445+ struct bpf_verifier_env * env ,
5446+ int idx )
5447+ {
5448+ struct bpf_verifier_state * cur = env -> cur_state ;
5449+ struct bpf_func_state * state = cur -> frame [cur -> curframe ];
5450+
5451+ return & env -> explored_states [(idx ^ state -> callsite ) % state_htab_size (env )];
5452+ }
5453+
5454+ static void init_explored_state (struct bpf_verifier_env * env , int idx )
5455+ {
5456+ env -> insn_aux_data [idx ].prune_point = true;
5457+ }
54405458
54415459/* t, w, e - match pseudo-code above:
54425460 * t - index of current instruction
@@ -5462,7 +5480,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
54625480
54635481 if (e == BRANCH )
54645482 /* mark branch target for state pruning */
5465- env -> explored_states [ w ] = STATE_LIST_MARK ;
5483+ init_explored_state ( env , w ) ;
54665484
54675485 if (insn_state [w ] == 0 ) {
54685486 /* tree-edge */
@@ -5530,9 +5548,9 @@ static int check_cfg(struct bpf_verifier_env *env)
55305548 else if (ret < 0 )
55315549 goto err_free ;
55325550 if (t + 1 < insn_cnt )
5533- env -> explored_states [ t + 1 ] = STATE_LIST_MARK ;
5551+ init_explored_state ( env , t + 1 ) ;
55345552 if (insns [t ].src_reg == BPF_PSEUDO_CALL ) {
5535- env -> explored_states [ t ] = STATE_LIST_MARK ;
5553+ init_explored_state ( env , t ) ;
55365554 ret = push_insn (t , t + insns [t ].imm + 1 , BRANCH , env );
55375555 if (ret == 1 )
55385556 goto peek_stack ;
@@ -5555,10 +5573,10 @@ static int check_cfg(struct bpf_verifier_env *env)
55555573 * after every call and jump
55565574 */
55575575 if (t + 1 < insn_cnt )
5558- env -> explored_states [ t + 1 ] = STATE_LIST_MARK ;
5576+ init_explored_state ( env , t + 1 ) ;
55595577 } else {
55605578 /* conditional jump with two edges */
5561- env -> explored_states [ t ] = STATE_LIST_MARK ;
5579+ init_explored_state ( env , t ) ;
55625580 ret = push_insn (t , t + 1 , FALLTHROUGH , env );
55635581 if (ret == 1 )
55645582 goto peek_stack ;
@@ -6006,12 +6024,10 @@ static void clean_live_states(struct bpf_verifier_env *env, int insn,
60066024 struct bpf_verifier_state_list * sl ;
60076025 int i ;
60086026
6009- sl = env -> explored_states [insn ];
6010- if (!sl )
6011- return ;
6012-
6013- while (sl != STATE_LIST_MARK ) {
6014- if (sl -> state .curframe != cur -> curframe )
6027+ sl = * explored_state (env , insn );
6028+ while (sl ) {
6029+ if (sl -> state .insn_idx != insn ||
6030+ sl -> state .curframe != cur -> curframe )
60156031 goto next ;
60166032 for (i = 0 ; i <= cur -> curframe ; i ++ )
60176033 if (sl -> state .frame [i ]-> callsite != cur -> frame [i ]-> callsite )
@@ -6365,18 +6381,21 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
63656381 struct bpf_verifier_state * cur = env -> cur_state , * new ;
63666382 int i , j , err , states_cnt = 0 ;
63676383
6368- pprev = & env -> explored_states [insn_idx ];
6369- sl = * pprev ;
6370-
6371- if (!sl )
6384+ if (!env -> insn_aux_data [insn_idx ].prune_point )
63726385 /* this 'insn_idx' instruction wasn't marked, so we will not
63736386 * be doing state search here
63746387 */
63756388 return 0 ;
63766389
6390+ pprev = explored_state (env , insn_idx );
6391+ sl = * pprev ;
6392+
63776393 clean_live_states (env , insn_idx , cur );
63786394
6379- while (sl != STATE_LIST_MARK ) {
6395+ while (sl ) {
6396+ states_cnt ++ ;
6397+ if (sl -> state .insn_idx != insn_idx )
6398+ goto next ;
63806399 if (states_equal (env , & sl -> state , cur )) {
63816400 sl -> hit_cnt ++ ;
63826401 /* reached equivalent register/stack state,
@@ -6394,7 +6413,6 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
63946413 return err ;
63956414 return 1 ;
63966415 }
6397- states_cnt ++ ;
63986416 sl -> miss_cnt ++ ;
63996417 /* heuristic to determine whether this state is beneficial
64006418 * to keep checking from state equivalence point of view.
@@ -6421,6 +6439,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
64216439 sl = * pprev ;
64226440 continue ;
64236441 }
6442+ next :
64246443 pprev = & sl -> next ;
64256444 sl = * pprev ;
64266445 }
@@ -6452,8 +6471,9 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
64526471 kfree (new_sl );
64536472 return err ;
64546473 }
6455- new_sl -> next = env -> explored_states [insn_idx ];
6456- env -> explored_states [insn_idx ] = new_sl ;
6474+ new -> insn_idx = insn_idx ;
6475+ new_sl -> next = * explored_state (env , insn_idx );
6476+ * explored_state (env , insn_idx ) = new_sl ;
64576477 /* connect new state to parentage chain. Current frame needs all
64586478 * registers connected. Only r6 - r9 of the callers are alive (pushed
64596479 * to the stack implicitly by JITs) so in callers' frames connect just
@@ -8131,16 +8151,15 @@ static void free_states(struct bpf_verifier_env *env)
81318151 if (!env -> explored_states )
81328152 return ;
81338153
8134- for (i = 0 ; i < env -> prog -> len ; i ++ ) {
8154+ for (i = 0 ; i < state_htab_size ( env ) ; i ++ ) {
81358155 sl = env -> explored_states [i ];
81368156
8137- if (sl )
8138- while (sl != STATE_LIST_MARK ) {
8139- sln = sl -> next ;
8140- free_verifier_state (& sl -> state , false);
8141- kfree (sl );
8142- sl = sln ;
8143- }
8157+ while (sl ) {
8158+ sln = sl -> next ;
8159+ free_verifier_state (& sl -> state , false);
8160+ kfree (sl );
8161+ sl = sln ;
8162+ }
81448163 }
81458164
81468165 kvfree (env -> explored_states );
@@ -8240,7 +8259,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
82408259 goto skip_full_check ;
82418260 }
82428261
8243- env -> explored_states = kvcalloc (env -> prog -> len ,
8262+ env -> explored_states = kvcalloc (state_htab_size ( env ) ,
82448263 sizeof (struct bpf_verifier_state_list * ),
82458264 GFP_USER );
82468265 ret = - ENOMEM ;
0 commit comments