@@ -181,6 +181,10 @@ struct verifier_stack_elem {
181
181
struct verifier_stack_elem * next ;
182
182
};
183
183
184
+ struct bpf_insn_aux_data {
185
+ enum bpf_reg_type ptr_type ; /* pointer type for load/store insns */
186
+ };
187
+
184
188
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
185
189
186
190
/* single container for all structs
@@ -197,6 +201,7 @@ struct verifier_env {
197
201
u32 id_gen ; /* used to generate unique reg IDs */
198
202
bool allow_ptr_leaks ;
199
203
bool seen_direct_write ;
204
+ struct bpf_insn_aux_data * insn_aux_data ; /* array of per-insn state */
200
205
};
201
206
202
207
#define BPF_COMPLEXITY_LIMIT_INSNS 65536
@@ -2344,7 +2349,7 @@ static int do_check(struct verifier_env *env)
2344
2349
return err ;
2345
2350
2346
2351
} else if (class == BPF_LDX ) {
2347
- enum bpf_reg_type src_reg_type ;
2352
+ enum bpf_reg_type * prev_src_type , src_reg_type ;
2348
2353
2349
2354
/* check for reserved fields is already done */
2350
2355
@@ -2374,16 +2379,18 @@ static int do_check(struct verifier_env *env)
2374
2379
continue ;
2375
2380
}
2376
2381
2377
- if (insn -> imm == 0 ) {
2382
+ prev_src_type = & env -> insn_aux_data [insn_idx ].ptr_type ;
2383
+
2384
+ if (* prev_src_type == NOT_INIT ) {
2378
2385
/* saw a valid insn
2379
2386
* dst_reg = *(u32 *)(src_reg + off)
2380
- * use reserved 'imm' field to mark this insn
2387
+ * save type to validate intersecting paths
2381
2388
*/
2382
- insn -> imm = src_reg_type ;
2389
+ * prev_src_type = src_reg_type ;
2383
2390
2384
- } else if (src_reg_type != insn -> imm &&
2391
+ } else if (src_reg_type != * prev_src_type &&
2385
2392
(src_reg_type == PTR_TO_CTX ||
2386
- insn -> imm == PTR_TO_CTX )) {
2393
+ * prev_src_type == PTR_TO_CTX )) {
2387
2394
/* ABuser program is trying to use the same insn
2388
2395
* dst_reg = *(u32*) (src_reg + off)
2389
2396
* with different pointer types:
@@ -2396,7 +2403,7 @@ static int do_check(struct verifier_env *env)
2396
2403
}
2397
2404
2398
2405
} else if (class == BPF_STX ) {
2399
- enum bpf_reg_type dst_reg_type ;
2406
+ enum bpf_reg_type * prev_dst_type , dst_reg_type ;
2400
2407
2401
2408
if (BPF_MODE (insn -> code ) == BPF_XADD ) {
2402
2409
err = check_xadd (env , insn );
@@ -2424,11 +2431,13 @@ static int do_check(struct verifier_env *env)
2424
2431
if (err )
2425
2432
return err ;
2426
2433
2427
- if (insn -> imm == 0 ) {
2428
- insn -> imm = dst_reg_type ;
2429
- } else if (dst_reg_type != insn -> imm &&
2434
+ prev_dst_type = & env -> insn_aux_data [insn_idx ].ptr_type ;
2435
+
2436
+ if (* prev_dst_type == NOT_INIT ) {
2437
+ * prev_dst_type = dst_reg_type ;
2438
+ } else if (dst_reg_type != * prev_dst_type &&
2430
2439
(dst_reg_type == PTR_TO_CTX ||
2431
- insn -> imm == PTR_TO_CTX )) {
2440
+ * prev_dst_type == PTR_TO_CTX )) {
2432
2441
verbose ("same insn cannot be used with different pointers\n" );
2433
2442
return - EINVAL ;
2434
2443
}
@@ -2686,10 +2695,11 @@ static void convert_pseudo_ld_imm64(struct verifier_env *env)
2686
2695
static int convert_ctx_accesses (struct verifier_env * env )
2687
2696
{
2688
2697
const struct bpf_verifier_ops * ops = env -> prog -> aux -> ops ;
2698
+ const int insn_cnt = env -> prog -> len ;
2689
2699
struct bpf_insn insn_buf [16 ], * insn ;
2690
2700
struct bpf_prog * new_prog ;
2691
2701
enum bpf_access_type type ;
2692
- int i , insn_cnt , cnt ;
2702
+ int i , cnt , delta = 0 ;
2693
2703
2694
2704
if (ops -> gen_prologue ) {
2695
2705
cnt = ops -> gen_prologue (insn_buf , env -> seen_direct_write ,
@@ -2703,18 +2713,16 @@ static int convert_ctx_accesses(struct verifier_env *env)
2703
2713
if (!new_prog )
2704
2714
return - ENOMEM ;
2705
2715
env -> prog = new_prog ;
2716
+ delta += cnt - 1 ;
2706
2717
}
2707
2718
}
2708
2719
2709
2720
if (!ops -> convert_ctx_access )
2710
2721
return 0 ;
2711
2722
2712
- insn_cnt = env -> prog -> len ;
2713
- insn = env -> prog -> insnsi ;
2723
+ insn = env -> prog -> insnsi + delta ;
2714
2724
2715
2725
for (i = 0 ; i < insn_cnt ; i ++ , insn ++ ) {
2716
- u32 insn_delta ;
2717
-
2718
2726
if (insn -> code == (BPF_LDX | BPF_MEM | BPF_W ) ||
2719
2727
insn -> code == (BPF_LDX | BPF_MEM | BPF_DW ))
2720
2728
type = BPF_READ ;
@@ -2724,11 +2732,8 @@ static int convert_ctx_accesses(struct verifier_env *env)
2724
2732
else
2725
2733
continue ;
2726
2734
2727
- if (insn -> imm != PTR_TO_CTX ) {
2728
- /* clear internal mark */
2729
- insn -> imm = 0 ;
2735
+ if (env -> insn_aux_data [i ].ptr_type != PTR_TO_CTX )
2730
2736
continue ;
2731
- }
2732
2737
2733
2738
cnt = ops -> convert_ctx_access (type , insn -> dst_reg , insn -> src_reg ,
2734
2739
insn -> off , insn_buf , env -> prog );
@@ -2737,18 +2742,16 @@ static int convert_ctx_accesses(struct verifier_env *env)
2737
2742
return - EINVAL ;
2738
2743
}
2739
2744
2740
- new_prog = bpf_patch_insn_single (env -> prog , i , insn_buf , cnt );
2745
+ new_prog = bpf_patch_insn_single (env -> prog , i + delta , insn_buf ,
2746
+ cnt );
2741
2747
if (!new_prog )
2742
2748
return - ENOMEM ;
2743
2749
2744
- insn_delta = cnt - 1 ;
2750
+ delta + = cnt - 1 ;
2745
2751
2746
2752
/* keep walking new program and skip insns we just inserted */
2747
2753
env -> prog = new_prog ;
2748
- insn = new_prog -> insnsi + i + insn_delta ;
2749
-
2750
- insn_cnt += insn_delta ;
2751
- i += insn_delta ;
2754
+ insn = new_prog -> insnsi + i + delta ;
2752
2755
}
2753
2756
2754
2757
return 0 ;
@@ -2792,6 +2795,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
2792
2795
if (!env )
2793
2796
return - ENOMEM ;
2794
2797
2798
+ env -> insn_aux_data = vzalloc (sizeof (struct bpf_insn_aux_data ) *
2799
+ (* prog )-> len );
2800
+ ret = - ENOMEM ;
2801
+ if (!env -> insn_aux_data )
2802
+ goto err_free_env ;
2795
2803
env -> prog = * prog ;
2796
2804
2797
2805
/* grab the mutex to protect few globals used by verifier */
@@ -2810,12 +2818,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
2810
2818
/* log_* values have to be sane */
2811
2819
if (log_size < 128 || log_size > UINT_MAX >> 8 ||
2812
2820
log_level == 0 || log_ubuf == NULL )
2813
- goto free_env ;
2821
+ goto err_unlock ;
2814
2822
2815
2823
ret = - ENOMEM ;
2816
2824
log_buf = vmalloc (log_size );
2817
2825
if (!log_buf )
2818
- goto free_env ;
2826
+ goto err_unlock ;
2819
2827
} else {
2820
2828
log_level = 0 ;
2821
2829
}
@@ -2884,14 +2892,16 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
2884
2892
free_log_buf :
2885
2893
if (log_level )
2886
2894
vfree (log_buf );
2887
- free_env :
2888
2895
if (!env -> prog -> aux -> used_maps )
2889
2896
/* if we didn't copy map pointers into bpf_prog_info, release
2890
2897
* them now. Otherwise free_bpf_prog_info() will release them.
2891
2898
*/
2892
2899
release_maps (env );
2893
2900
* prog = env -> prog ;
2894
- kfree ( env );
2901
+ err_unlock :
2895
2902
mutex_unlock (& bpf_verifier_lock );
2903
+ vfree (env -> insn_aux_data );
2904
+ err_free_env :
2905
+ kfree (env );
2896
2906
return ret ;
2897
2907
}
0 commit comments