@@ -5856,6 +5856,14 @@ static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
5856
5856
return & env -> insn_aux_data [env -> insn_idx ];
5857
5857
}
5858
5858
5859
+ enum {
5860
+ REASON_BOUNDS = -1 ,
5861
+ REASON_TYPE = -2 ,
5862
+ REASON_PATHS = -3 ,
5863
+ REASON_LIMIT = -4 ,
5864
+ REASON_STACK = -5 ,
5865
+ };
5866
+
5859
5867
static int retrieve_ptr_limit (const struct bpf_reg_state * ptr_reg ,
5860
5868
const struct bpf_reg_state * off_reg ,
5861
5869
u32 * alu_limit , u8 opcode )
@@ -5867,7 +5875,7 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
5867
5875
5868
5876
if (!tnum_is_const (off_reg -> var_off ) &&
5869
5877
(off_reg -> smin_value < 0 ) != (off_reg -> smax_value < 0 ))
5870
- return - EACCES ;
5878
+ return REASON_BOUNDS ;
5871
5879
5872
5880
switch (ptr_reg -> type ) {
5873
5881
case PTR_TO_STACK :
@@ -5894,11 +5902,11 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
5894
5902
}
5895
5903
break ;
5896
5904
default :
5897
- return - EINVAL ;
5905
+ return REASON_TYPE ;
5898
5906
}
5899
5907
5900
5908
if (ptr_limit >= max )
5901
- return - ERANGE ;
5909
+ return REASON_LIMIT ;
5902
5910
* alu_limit = ptr_limit ;
5903
5911
return 0 ;
5904
5912
}
@@ -5918,7 +5926,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
5918
5926
if (aux -> alu_state &&
5919
5927
(aux -> alu_state != alu_state ||
5920
5928
aux -> alu_limit != alu_limit ))
5921
- return - EACCES ;
5929
+ return REASON_PATHS ;
5922
5930
5923
5931
/* Corresponding fixup done in fixup_bpf_calls(). */
5924
5932
aux -> alu_state = alu_state ;
@@ -5991,7 +5999,46 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
5991
5999
ret = push_stack (env , env -> insn_idx + 1 , env -> insn_idx , true);
5992
6000
if (!ptr_is_dst_reg && ret )
5993
6001
* dst_reg = tmp ;
5994
- return !ret ? - EFAULT : 0 ;
6002
+ return !ret ? REASON_STACK : 0 ;
6003
+ }
6004
+
6005
+ static int sanitize_err (struct bpf_verifier_env * env ,
6006
+ const struct bpf_insn * insn , int reason ,
6007
+ const struct bpf_reg_state * off_reg ,
6008
+ const struct bpf_reg_state * dst_reg )
6009
+ {
6010
+ static const char * err = "pointer arithmetic with it prohibited for !root" ;
6011
+ const char * op = BPF_OP (insn -> code ) == BPF_ADD ? "add" : "sub" ;
6012
+ u32 dst = insn -> dst_reg , src = insn -> src_reg ;
6013
+
6014
+ switch (reason ) {
6015
+ case REASON_BOUNDS :
6016
+ verbose (env , "R%d has unknown scalar with mixed signed bounds, %s\n" ,
6017
+ off_reg == dst_reg ? dst : src , err );
6018
+ break ;
6019
+ case REASON_TYPE :
6020
+ verbose (env , "R%d has pointer with unsupported alu operation, %s\n" ,
6021
+ off_reg == dst_reg ? src : dst , err );
6022
+ break ;
6023
+ case REASON_PATHS :
6024
+ verbose (env , "R%d tried to %s from different maps, paths or scalars, %s\n" ,
6025
+ dst , op , err );
6026
+ break ;
6027
+ case REASON_LIMIT :
6028
+ verbose (env , "R%d tried to %s beyond pointer bounds, %s\n" ,
6029
+ dst , op , err );
6030
+ break ;
6031
+ case REASON_STACK :
6032
+ verbose (env , "R%d could not be pushed for speculative verification, %s\n" ,
6033
+ dst , err );
6034
+ break ;
6035
+ default :
6036
+ verbose (env , "verifier internal error: unknown reason (%d)\n" ,
6037
+ reason );
6038
+ break ;
6039
+ }
6040
+
6041
+ return - EACCES ;
5995
6042
}
5996
6043
5997
6044
/* check that stack access falls within stack limits and that 'reg' doesn't
@@ -6116,10 +6163,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
6116
6163
switch (opcode ) {
6117
6164
case BPF_ADD :
6118
6165
ret = sanitize_ptr_alu (env , insn , ptr_reg , off_reg , dst_reg );
6119
- if (ret < 0 ) {
6120
- verbose (env , "R%d tried to add from different maps, paths, or prohibited types\n" , dst );
6121
- return ret ;
6122
- }
6166
+ if (ret < 0 )
6167
+ return sanitize_err (env , insn , ret , off_reg , dst_reg );
6168
+
6123
6169
/* We can take a fixed offset as long as it doesn't overflow
6124
6170
* the s32 'off' field
6125
6171
*/
@@ -6171,10 +6217,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
6171
6217
break ;
6172
6218
case BPF_SUB :
6173
6219
ret = sanitize_ptr_alu (env , insn , ptr_reg , off_reg , dst_reg );
6174
- if (ret < 0 ) {
6175
- verbose (env , "R%d tried to sub from different maps, paths, or prohibited types\n" , dst );
6176
- return ret ;
6177
- }
6220
+ if (ret < 0 )
6221
+ return sanitize_err (env , insn , ret , off_reg , dst_reg );
6222
+
6178
6223
if (dst_reg == off_reg ) {
6179
6224
/* scalar -= pointer. Creates an unknown scalar */
6180
6225
verbose (env , "R%d tried to subtract pointer from scalar\n" ,
@@ -6863,9 +6908,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
6863
6908
s32 s32_min_val , s32_max_val ;
6864
6909
u32 u32_min_val , u32_max_val ;
6865
6910
u64 insn_bitness = (BPF_CLASS (insn -> code ) == BPF_ALU64 ) ? 64 : 32 ;
6866
- u32 dst = insn -> dst_reg ;
6867
- int ret ;
6868
6911
bool alu32 = (BPF_CLASS (insn -> code ) != BPF_ALU64 );
6912
+ int ret ;
6869
6913
6870
6914
smin_val = src_reg .smin_value ;
6871
6915
smax_val = src_reg .smax_value ;
@@ -6924,20 +6968,16 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
6924
6968
switch (opcode ) {
6925
6969
case BPF_ADD :
6926
6970
ret = sanitize_val_alu (env , insn );
6927
- if (ret < 0 ) {
6928
- verbose (env , "R%d tried to add from different pointers or scalars\n" , dst );
6929
- return ret ;
6930
- }
6971
+ if (ret < 0 )
6972
+ return sanitize_err (env , insn , ret , NULL , NULL );
6931
6973
scalar32_min_max_add (dst_reg , & src_reg );
6932
6974
scalar_min_max_add (dst_reg , & src_reg );
6933
6975
dst_reg -> var_off = tnum_add (dst_reg -> var_off , src_reg .var_off );
6934
6976
break ;
6935
6977
case BPF_SUB :
6936
6978
ret = sanitize_val_alu (env , insn );
6937
- if (ret < 0 ) {
6938
- verbose (env , "R%d tried to sub from different pointers or scalars\n" , dst );
6939
- return ret ;
6940
- }
6979
+ if (ret < 0 )
6980
+ return sanitize_err (env , insn , ret , NULL , NULL );
6941
6981
scalar32_min_max_sub (dst_reg , & src_reg );
6942
6982
scalar_min_max_sub (dst_reg , & src_reg );
6943
6983
dst_reg -> var_off = tnum_sub (dst_reg -> var_off , src_reg .var_off );
0 commit comments