@@ -2739,7 +2739,9 @@ static int check_packet_access(struct bpf_verifier_env *env, u32 regno, int off,
2739
2739
regno );
2740
2740
return - EACCES ;
2741
2741
}
2742
- err = __check_mem_access (env , regno , off , size , reg -> range ,
2742
+
2743
+ err = reg -> range < 0 ? - EINVAL :
2744
+ __check_mem_access (env , regno , off , size , reg -> range ,
2743
2745
zero_size_allowed );
2744
2746
if (err ) {
2745
2747
verbose (env , "R%d offset is outside of the packet\n" , regno );
@@ -4697,6 +4699,32 @@ static void clear_all_pkt_pointers(struct bpf_verifier_env *env)
4697
4699
__clear_all_pkt_pointers (env , vstate -> frame [i ]);
4698
4700
}
4699
4701
4702
+ enum {
4703
+ AT_PKT_END = -1 ,
4704
+ BEYOND_PKT_END = -2 ,
4705
+ };
4706
+
4707
+ static void mark_pkt_end (struct bpf_verifier_state * vstate , int regn , bool range_open )
4708
+ {
4709
+ struct bpf_func_state * state = vstate -> frame [vstate -> curframe ];
4710
+ struct bpf_reg_state * reg = & state -> regs [regn ];
4711
+
4712
+ if (reg -> type != PTR_TO_PACKET )
4713
+ /* PTR_TO_PACKET_META is not supported yet */
4714
+ return ;
4715
+
4716
+ /* The 'reg' is pkt > pkt_end or pkt >= pkt_end.
4717
+ * How far beyond pkt_end it goes is unknown.
4718
+ * if (!range_open) it's the case of pkt >= pkt_end
4719
+ * if (range_open) it's the case of pkt > pkt_end
4720
+ * hence this pointer is at least 1 byte bigger than pkt_end
4721
+ */
4722
+ if (range_open )
4723
+ reg -> range = BEYOND_PKT_END ;
4724
+ else
4725
+ reg -> range = AT_PKT_END ;
4726
+ }
4727
+
4700
4728
static void release_reg_references (struct bpf_verifier_env * env ,
4701
4729
struct bpf_func_state * state ,
4702
4730
int ref_obj_id )
@@ -6708,7 +6736,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
6708
6736
6709
6737
static void __find_good_pkt_pointers (struct bpf_func_state * state ,
6710
6738
struct bpf_reg_state * dst_reg ,
6711
- enum bpf_reg_type type , u16 new_range )
6739
+ enum bpf_reg_type type , int new_range )
6712
6740
{
6713
6741
struct bpf_reg_state * reg ;
6714
6742
int i ;
@@ -6733,8 +6761,7 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,
6733
6761
enum bpf_reg_type type ,
6734
6762
bool range_right_open )
6735
6763
{
6736
- u16 new_range ;
6737
- int i ;
6764
+ int new_range , i ;
6738
6765
6739
6766
if (dst_reg -> off < 0 ||
6740
6767
(dst_reg -> off == 0 && range_right_open ))
@@ -6985,6 +7012,67 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode,
6985
7012
return is_branch64_taken (reg , val , opcode );
6986
7013
}
6987
7014
7015
+ static int flip_opcode (u32 opcode )
7016
+ {
7017
+ /* How can we transform "a <op> b" into "b <op> a"? */
7018
+ static const u8 opcode_flip [16 ] = {
7019
+ /* these stay the same */
7020
+ [BPF_JEQ >> 4 ] = BPF_JEQ ,
7021
+ [BPF_JNE >> 4 ] = BPF_JNE ,
7022
+ [BPF_JSET >> 4 ] = BPF_JSET ,
7023
+ /* these swap "lesser" and "greater" (L and G in the opcodes) */
7024
+ [BPF_JGE >> 4 ] = BPF_JLE ,
7025
+ [BPF_JGT >> 4 ] = BPF_JLT ,
7026
+ [BPF_JLE >> 4 ] = BPF_JGE ,
7027
+ [BPF_JLT >> 4 ] = BPF_JGT ,
7028
+ [BPF_JSGE >> 4 ] = BPF_JSLE ,
7029
+ [BPF_JSGT >> 4 ] = BPF_JSLT ,
7030
+ [BPF_JSLE >> 4 ] = BPF_JSGE ,
7031
+ [BPF_JSLT >> 4 ] = BPF_JSGT
7032
+ };
7033
+ return opcode_flip [opcode >> 4 ];
7034
+ }
7035
+
7036
+ static int is_pkt_ptr_branch_taken (struct bpf_reg_state * dst_reg ,
7037
+ struct bpf_reg_state * src_reg ,
7038
+ u8 opcode )
7039
+ {
7040
+ struct bpf_reg_state * pkt ;
7041
+
7042
+ if (src_reg -> type == PTR_TO_PACKET_END ) {
7043
+ pkt = dst_reg ;
7044
+ } else if (dst_reg -> type == PTR_TO_PACKET_END ) {
7045
+ pkt = src_reg ;
7046
+ opcode = flip_opcode (opcode );
7047
+ } else {
7048
+ return -1 ;
7049
+ }
7050
+
7051
+ if (pkt -> range >= 0 )
7052
+ return -1 ;
7053
+
7054
+ switch (opcode ) {
7055
+ case BPF_JLE :
7056
+ /* pkt <= pkt_end */
7057
+ fallthrough ;
7058
+ case BPF_JGT :
7059
+ /* pkt > pkt_end */
7060
+ if (pkt -> range == BEYOND_PKT_END )
7061
+ /* pkt has at last one extra byte beyond pkt_end */
7062
+ return opcode == BPF_JGT ;
7063
+ break ;
7064
+ case BPF_JLT :
7065
+ /* pkt < pkt_end */
7066
+ fallthrough ;
7067
+ case BPF_JGE :
7068
+ /* pkt >= pkt_end */
7069
+ if (pkt -> range == BEYOND_PKT_END || pkt -> range == AT_PKT_END )
7070
+ return opcode == BPF_JGE ;
7071
+ break ;
7072
+ }
7073
+ return -1 ;
7074
+ }
7075
+
6988
7076
/* Adjusts the register min/max values in the case that the dst_reg is the
6989
7077
* variable register that we are working on, and src_reg is a constant or we're
6990
7078
* simply doing a BPF_K check.
@@ -7148,23 +7236,7 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
7148
7236
u64 val , u32 val32 ,
7149
7237
u8 opcode , bool is_jmp32 )
7150
7238
{
7151
- /* How can we transform "a <op> b" into "b <op> a"? */
7152
- static const u8 opcode_flip [16 ] = {
7153
- /* these stay the same */
7154
- [BPF_JEQ >> 4 ] = BPF_JEQ ,
7155
- [BPF_JNE >> 4 ] = BPF_JNE ,
7156
- [BPF_JSET >> 4 ] = BPF_JSET ,
7157
- /* these swap "lesser" and "greater" (L and G in the opcodes) */
7158
- [BPF_JGE >> 4 ] = BPF_JLE ,
7159
- [BPF_JGT >> 4 ] = BPF_JLT ,
7160
- [BPF_JLE >> 4 ] = BPF_JGE ,
7161
- [BPF_JLT >> 4 ] = BPF_JGT ,
7162
- [BPF_JSGE >> 4 ] = BPF_JSLE ,
7163
- [BPF_JSGT >> 4 ] = BPF_JSLT ,
7164
- [BPF_JSLE >> 4 ] = BPF_JSGE ,
7165
- [BPF_JSLT >> 4 ] = BPF_JSGT
7166
- };
7167
- opcode = opcode_flip [opcode >> 4 ];
7239
+ opcode = flip_opcode (opcode );
7168
7240
/* This uses zero as "not present in table"; luckily the zero opcode,
7169
7241
* BPF_JA, can't get here.
7170
7242
*/
@@ -7346,13 +7418,15 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
7346
7418
/* pkt_data' > pkt_end, pkt_meta' > pkt_data */
7347
7419
find_good_pkt_pointers (this_branch , dst_reg ,
7348
7420
dst_reg -> type , false);
7421
+ mark_pkt_end (other_branch , insn -> dst_reg , true);
7349
7422
} else if ((dst_reg -> type == PTR_TO_PACKET_END &&
7350
7423
src_reg -> type == PTR_TO_PACKET ) ||
7351
7424
(reg_is_init_pkt_pointer (dst_reg , PTR_TO_PACKET ) &&
7352
7425
src_reg -> type == PTR_TO_PACKET_META )) {
7353
7426
/* pkt_end > pkt_data', pkt_data > pkt_meta' */
7354
7427
find_good_pkt_pointers (other_branch , src_reg ,
7355
7428
src_reg -> type , true);
7429
+ mark_pkt_end (this_branch , insn -> src_reg , false);
7356
7430
} else {
7357
7431
return false;
7358
7432
}
@@ -7365,13 +7439,15 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
7365
7439
/* pkt_data' < pkt_end, pkt_meta' < pkt_data */
7366
7440
find_good_pkt_pointers (other_branch , dst_reg ,
7367
7441
dst_reg -> type , true);
7442
+ mark_pkt_end (this_branch , insn -> dst_reg , false);
7368
7443
} else if ((dst_reg -> type == PTR_TO_PACKET_END &&
7369
7444
src_reg -> type == PTR_TO_PACKET ) ||
7370
7445
(reg_is_init_pkt_pointer (dst_reg , PTR_TO_PACKET ) &&
7371
7446
src_reg -> type == PTR_TO_PACKET_META )) {
7372
7447
/* pkt_end < pkt_data', pkt_data > pkt_meta' */
7373
7448
find_good_pkt_pointers (this_branch , src_reg ,
7374
7449
src_reg -> type , false);
7450
+ mark_pkt_end (other_branch , insn -> src_reg , true);
7375
7451
} else {
7376
7452
return false;
7377
7453
}
@@ -7384,13 +7460,15 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
7384
7460
/* pkt_data' >= pkt_end, pkt_meta' >= pkt_data */
7385
7461
find_good_pkt_pointers (this_branch , dst_reg ,
7386
7462
dst_reg -> type , true);
7463
+ mark_pkt_end (other_branch , insn -> dst_reg , false);
7387
7464
} else if ((dst_reg -> type == PTR_TO_PACKET_END &&
7388
7465
src_reg -> type == PTR_TO_PACKET ) ||
7389
7466
(reg_is_init_pkt_pointer (dst_reg , PTR_TO_PACKET ) &&
7390
7467
src_reg -> type == PTR_TO_PACKET_META )) {
7391
7468
/* pkt_end >= pkt_data', pkt_data >= pkt_meta' */
7392
7469
find_good_pkt_pointers (other_branch , src_reg ,
7393
7470
src_reg -> type , false);
7471
+ mark_pkt_end (this_branch , insn -> src_reg , true);
7394
7472
} else {
7395
7473
return false;
7396
7474
}
@@ -7403,13 +7481,15 @@ static bool try_match_pkt_pointers(const struct bpf_insn *insn,
7403
7481
/* pkt_data' <= pkt_end, pkt_meta' <= pkt_data */
7404
7482
find_good_pkt_pointers (other_branch , dst_reg ,
7405
7483
dst_reg -> type , false);
7484
+ mark_pkt_end (this_branch , insn -> dst_reg , true);
7406
7485
} else if ((dst_reg -> type == PTR_TO_PACKET_END &&
7407
7486
src_reg -> type == PTR_TO_PACKET ) ||
7408
7487
(reg_is_init_pkt_pointer (dst_reg , PTR_TO_PACKET ) &&
7409
7488
src_reg -> type == PTR_TO_PACKET_META )) {
7410
7489
/* pkt_end <= pkt_data', pkt_data <= pkt_meta' */
7411
7490
find_good_pkt_pointers (this_branch , src_reg ,
7412
7491
src_reg -> type , true);
7492
+ mark_pkt_end (other_branch , insn -> src_reg , false);
7413
7493
} else {
7414
7494
return false;
7415
7495
}
@@ -7509,6 +7589,10 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
7509
7589
src_reg -> var_off .value ,
7510
7590
opcode ,
7511
7591
is_jmp32 );
7592
+ } else if (reg_is_pkt_pointer_any (dst_reg ) &&
7593
+ reg_is_pkt_pointer_any (src_reg ) &&
7594
+ !is_jmp32 ) {
7595
+ pred = is_pkt_ptr_branch_taken (dst_reg , src_reg , opcode );
7512
7596
}
7513
7597
7514
7598
if (pred >= 0 ) {
@@ -7517,7 +7601,8 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
7517
7601
*/
7518
7602
if (!__is_pointer_value (false, dst_reg ))
7519
7603
err = mark_chain_precision (env , insn -> dst_reg );
7520
- if (BPF_SRC (insn -> code ) == BPF_X && !err )
7604
+ if (BPF_SRC (insn -> code ) == BPF_X && !err &&
7605
+ !__is_pointer_value (false, src_reg ))
7521
7606
err = mark_chain_precision (env , insn -> src_reg );
7522
7607
if (err )
7523
7608
return err ;
0 commit comments