@@ -1660,6 +1660,13 @@ static void free_func_state(struct bpf_func_state *state)
1660
1660
kfree(state);
1661
1661
}
1662
1662
1663
+ static void clear_jmp_history(struct bpf_verifier_state *state)
1664
+ {
1665
+ kfree(state->jmp_history);
1666
+ state->jmp_history = NULL;
1667
+ state->jmp_history_cnt = 0;
1668
+ }
1669
+
1663
1670
static void free_verifier_state(struct bpf_verifier_state *state,
1664
1671
bool free_self)
1665
1672
{
@@ -1670,6 +1677,7 @@ static void free_verifier_state(struct bpf_verifier_state *state,
1670
1677
state->frame[i] = NULL;
1671
1678
}
1672
1679
kfree(state->refs);
1680
+ clear_jmp_history(state);
1673
1681
if (free_self)
1674
1682
kfree(state);
1675
1683
}
@@ -1734,6 +1742,13 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
1734
1742
struct bpf_func_state *dst;
1735
1743
int i, err;
1736
1744
1745
+ dst_state->jmp_history = copy_array(dst_state->jmp_history, src->jmp_history,
1746
+ src->jmp_history_cnt, sizeof(*dst_state->jmp_history),
1747
+ GFP_USER);
1748
+ if (!dst_state->jmp_history)
1749
+ return -ENOMEM;
1750
+ dst_state->jmp_history_cnt = src->jmp_history_cnt;
1751
+
1737
1752
/* if dst has more stack frames then src frame, free them, this is also
1738
1753
* necessary in case of exceptional exits using bpf_throw.
1739
1754
*/
@@ -1751,8 +1766,6 @@ static int copy_verifier_state(struct bpf_verifier_state *dst_state,
1751
1766
dst_state->parent = src->parent;
1752
1767
dst_state->first_insn_idx = src->first_insn_idx;
1753
1768
dst_state->last_insn_idx = src->last_insn_idx;
1754
- dst_state->insn_hist_start = src->insn_hist_start;
1755
- dst_state->insn_hist_end = src->insn_hist_end;
1756
1769
dst_state->dfs_depth = src->dfs_depth;
1757
1770
dst_state->callback_unroll_depth = src->callback_unroll_depth;
1758
1771
dst_state->used_as_loop_entry = src->used_as_loop_entry;
@@ -2820,14 +2833,9 @@ static struct bpf_verifier_state *push_async_cb(struct bpf_verifier_env *env,
2820
2833
* The caller state doesn't matter.
2821
2834
* This is async callback. It starts in a fresh stack.
2822
2835
* Initialize it similar to do_check_common().
2823
- * But we do need to make sure to not clobber insn_hist, so we keep
2824
- * chaining insn_hist_start/insn_hist_end indices as for a normal
2825
- * child state.
2826
2836
*/
2827
2837
elem->st.branches = 1;
2828
2838
elem->st.in_sleepable = is_sleepable;
2829
- elem->st.insn_hist_start = env->cur_state->insn_hist_end;
2830
- elem->st.insn_hist_end = elem->st.insn_hist_start;
2831
2839
frame = kzalloc(sizeof(*frame), GFP_KERNEL);
2832
2840
if (!frame)
2833
2841
goto err;
@@ -3856,10 +3864,11 @@ static void linked_regs_unpack(u64 val, struct linked_regs *s)
3856
3864
}
3857
3865
3858
3866
/* for any branch, call, exit record the history of jmps in the given state */
3859
- static int push_insn_history (struct bpf_verifier_env *env, struct bpf_verifier_state *cur,
3860
- int insn_flags, u64 linked_regs)
3867
+ static int push_jmp_history (struct bpf_verifier_env *env, struct bpf_verifier_state *cur,
3868
+ int insn_flags, u64 linked_regs)
3861
3869
{
3862
- struct bpf_insn_hist_entry *p;
3870
+ u32 cnt = cur->jmp_history_cnt;
3871
+ struct bpf_jmp_history_entry *p;
3863
3872
size_t alloc_size;
3864
3873
3865
3874
/* combine instruction flags if we already recorded this instruction */
@@ -3879,32 +3888,29 @@ static int push_insn_history(struct bpf_verifier_env *env, struct bpf_verifier_s
3879
3888
return 0;
3880
3889
}
3881
3890
3882
- if (cur->insn_hist_end + 1 > env->insn_hist_cap) {
3883
- alloc_size = size_mul(cur->insn_hist_end + 1, sizeof(*p));
3884
- p = kvrealloc(env->insn_hist, alloc_size, GFP_USER);
3885
- if (!p)
3886
- return -ENOMEM;
3887
- env->insn_hist = p;
3888
- env->insn_hist_cap = alloc_size / sizeof(*p);
3889
- }
3891
+ cnt++;
3892
+ alloc_size = kmalloc_size_roundup(size_mul(cnt, sizeof(*p)));
3893
+ p = krealloc(cur->jmp_history, alloc_size, GFP_USER);
3894
+ if (!p)
3895
+ return -ENOMEM;
3896
+ cur->jmp_history = p;
3890
3897
3891
- p = &env->insn_hist[cur->insn_hist_end ];
3898
+ p = &cur->jmp_history[cnt - 1 ];
3892
3899
p->idx = env->insn_idx;
3893
3900
p->prev_idx = env->prev_insn_idx;
3894
3901
p->flags = insn_flags;
3895
3902
p->linked_regs = linked_regs;
3896
-
3897
- cur->insn_hist_end++;
3903
+ cur->jmp_history_cnt = cnt;
3898
3904
env->cur_hist_ent = p;
3899
3905
3900
3906
return 0;
3901
3907
}
3902
3908
3903
- static struct bpf_insn_hist_entry *get_insn_hist_entry (struct bpf_verifier_env *env ,
3904
- u32 hist_start, u32 hist_end, int insn_idx)
3909
+ static struct bpf_jmp_history_entry *get_jmp_hist_entry (struct bpf_verifier_state *st ,
3910
+ u32 hist_end, int insn_idx)
3905
3911
{
3906
- if (hist_end > hist_start && env->insn_hist [hist_end - 1].idx == insn_idx)
3907
- return &env->insn_hist [hist_end - 1];
3912
+ if (hist_end > 0 && st->jmp_history [hist_end - 1].idx == insn_idx)
3913
+ return &st->jmp_history [hist_end - 1];
3908
3914
return NULL;
3909
3915
}
3910
3916
@@ -3921,26 +3927,25 @@ static struct bpf_insn_hist_entry *get_insn_hist_entry(struct bpf_verifier_env *
3921
3927
* history entry recording a jump from last instruction of parent state and
3922
3928
* first instruction of given state.
3923
3929
*/
3924
- static int get_prev_insn_idx(const struct bpf_verifier_env *env,
3925
- struct bpf_verifier_state *st,
3926
- int insn_idx, u32 hist_start, u32 *hist_endp)
3930
+ static int get_prev_insn_idx(struct bpf_verifier_state *st, int i,
3931
+ u32 *history)
3927
3932
{
3928
- u32 hist_end = *hist_endp;
3929
- u32 cnt = hist_end - hist_start;
3933
+ u32 cnt = *history;
3930
3934
3931
- if (insn_idx == st->first_insn_idx) {
3935
+ if (i == st->first_insn_idx) {
3932
3936
if (cnt == 0)
3933
3937
return -ENOENT;
3934
- if (cnt == 1 && env->insn_hist[hist_start ].idx == insn_idx )
3938
+ if (cnt == 1 && st->jmp_history[0 ].idx == i )
3935
3939
return -ENOENT;
3936
3940
}
3937
3941
3938
- if (cnt && env->insn_hist[hist_end - 1].idx == insn_idx ) {
3939
- (*hist_endp)-- ;
3940
- return env->insn_hist[hist_end - 1].prev_idx ;
3942
+ if (cnt && st->jmp_history[cnt - 1].idx == i ) {
3943
+ i = st->jmp_history[cnt - 1].prev_idx ;
3944
+ (*history)-- ;
3941
3945
} else {
3942
- return insn_idx - 1 ;
3946
+ i-- ;
3943
3947
}
3948
+ return i;
3944
3949
}
3945
3950
3946
3951
static const char *disasm_kfunc_name(void *data, const struct bpf_insn *insn)
@@ -4121,7 +4126,7 @@ static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask)
4121
4126
/* If any register R in hist->linked_regs is marked as precise in bt,
4122
4127
* do bt_set_frame_{reg,slot}(bt, R) for all registers in hist->linked_regs.
4123
4128
*/
4124
- static void bt_sync_linked_regs(struct backtrack_state *bt, struct bpf_insn_hist_entry *hist)
4129
+ static void bt_sync_linked_regs(struct backtrack_state *bt, struct bpf_jmp_history_entry *hist)
4125
4130
{
4126
4131
struct linked_regs linked_regs;
4127
4132
bool some_precise = false;
@@ -4166,7 +4171,7 @@ static bool calls_callback(struct bpf_verifier_env *env, int insn_idx);
4166
4171
* - *was* processed previously during backtracking.
4167
4172
*/
4168
4173
static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
4169
- struct bpf_insn_hist_entry *hist, struct backtrack_state *bt)
4174
+ struct bpf_jmp_history_entry *hist, struct backtrack_state *bt)
4170
4175
{
4171
4176
struct bpf_insn *insn = env->prog->insnsi + idx;
4172
4177
u8 class = BPF_CLASS(insn->code);
@@ -4584,7 +4589,7 @@ static void mark_all_scalars_imprecise(struct bpf_verifier_env *env, struct bpf_
4584
4589
* SCALARS, as well as any other registers and slots that contribute to
4585
4590
* a tracked state of given registers/stack slots, depending on specific BPF
4586
4591
* assembly instructions (see backtrack_insns() for exact instruction handling
4587
- * logic). This backtracking relies on recorded insn_hist and is able to
4592
+ * logic). This backtracking relies on recorded jmp_history and is able to
4588
4593
* traverse entire chain of parent states. This process ends only when all the
4589
4594
* necessary registers/slots and their transitive dependencies are marked as
4590
4595
* precise.
@@ -4701,9 +4706,8 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
4701
4706
4702
4707
for (;;) {
4703
4708
DECLARE_BITMAP(mask, 64);
4704
- u32 hist_start = st->insn_hist_start;
4705
- u32 hist_end = st->insn_hist_end;
4706
- struct bpf_insn_hist_entry *hist;
4709
+ u32 history = st->jmp_history_cnt;
4710
+ struct bpf_jmp_history_entry *hist;
4707
4711
4708
4712
if (env->log.level & BPF_LOG_LEVEL2) {
4709
4713
verbose(env, "mark_precise: frame%d: last_idx %d first_idx %d subseq_idx %d \n",
@@ -4741,7 +4745,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
4741
4745
err = 0;
4742
4746
skip_first = false;
4743
4747
} else {
4744
- hist = get_insn_hist_entry(env, hist_start, hist_end , i);
4748
+ hist = get_jmp_hist_entry(st, history , i);
4745
4749
err = backtrack_insn(env, i, subseq_idx, hist, bt);
4746
4750
}
4747
4751
if (err == -ENOTSUPP) {
@@ -4758,7 +4762,7 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
4758
4762
*/
4759
4763
return 0;
4760
4764
subseq_idx = i;
4761
- i = get_prev_insn_idx(env, st, i, hist_start, &hist_end );
4765
+ i = get_prev_insn_idx(st, i, &history );
4762
4766
if (i == -ENOENT)
4763
4767
break;
4764
4768
if (i >= env->prog->len) {
@@ -5122,7 +5126,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
5122
5126
}
5123
5127
5124
5128
if (insn_flags)
5125
- return push_insn_history (env, env->cur_state, insn_flags, 0);
5129
+ return push_jmp_history (env, env->cur_state, insn_flags, 0);
5126
5130
return 0;
5127
5131
}
5128
5132
@@ -5429,7 +5433,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
5429
5433
insn_flags = 0; /* we are not restoring spilled register */
5430
5434
}
5431
5435
if (insn_flags)
5432
- return push_insn_history (env, env->cur_state, insn_flags, 0);
5436
+ return push_jmp_history (env, env->cur_state, insn_flags, 0);
5433
5437
return 0;
5434
5438
}
5435
5439
@@ -16496,7 +16500,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
16496
16500
}
16497
16501
16498
16502
if (insn_flags) {
16499
- err = push_insn_history (env, this_branch, insn_flags, 0);
16503
+ err = push_jmp_history (env, this_branch, insn_flags, 0);
16500
16504
if (err)
16501
16505
return err;
16502
16506
}
@@ -16554,7 +16558,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
16554
16558
if (dst_reg->type == SCALAR_VALUE && dst_reg->id)
16555
16559
collect_linked_regs(this_branch, dst_reg->id, &linked_regs);
16556
16560
if (linked_regs.cnt > 1) {
16557
- err = push_insn_history (env, this_branch, 0, linked_regs_pack(&linked_regs));
16561
+ err = push_jmp_history (env, this_branch, 0, linked_regs_pack(&linked_regs));
16558
16562
if (err)
16559
16563
return err;
16560
16564
}
@@ -19052,7 +19056,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
19052
19056
19053
19057
force_new_state = env->test_state_freq || is_force_checkpoint(env, insn_idx) ||
19054
19058
/* Avoid accumulating infinitely long jmp history */
19055
- cur->insn_hist_end - cur->insn_hist_start > 40;
19059
+ cur->jmp_history_cnt > 40;
19056
19060
19057
19061
/* bpf progs typically have pruning point every 4 instructions
19058
19062
* http://vger.kernel.org/bpfconf2019.html#session-1
@@ -19251,7 +19255,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
19251
19255
* the current state.
19252
19256
*/
19253
19257
if (is_jmp_point(env, env->insn_idx))
19254
- err = err ? : push_insn_history (env, cur, 0, 0);
19258
+ err = err ? : push_jmp_history (env, cur, 0, 0);
19255
19259
err = err ? : propagate_precision(env, &sl->state);
19256
19260
if (err)
19257
19261
return err;
@@ -19333,8 +19337,8 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
19333
19337
19334
19338
cur->parent = new;
19335
19339
cur->first_insn_idx = insn_idx;
19336
- cur->insn_hist_start = cur->insn_hist_end;
19337
19340
cur->dfs_depth = new->dfs_depth + 1;
19341
+ clear_jmp_history(cur);
19338
19342
list_add(&new_sl->node, head);
19339
19343
19340
19344
/* connect new state to parentage chain. Current frame needs all
@@ -19704,7 +19708,7 @@ static int do_check(struct bpf_verifier_env *env)
19704
19708
}
19705
19709
19706
19710
if (is_jmp_point(env, env->insn_idx)) {
19707
- err = push_insn_history (env, state, 0, 0);
19711
+ err = push_jmp_history (env, state, 0, 0);
19708
19712
if (err)
19709
19713
return err;
19710
19714
}
@@ -24291,7 +24295,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
24291
24295
if (!is_priv)
24292
24296
mutex_unlock(&bpf_verifier_lock);
24293
24297
vfree(env->insn_aux_data);
24294
- kvfree(env->insn_hist);
24295
24298
err_free_env:
24296
24299
kvfree(env->cfg.insn_postorder);
24297
24300
kvfree(env);
0 commit comments