aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJiong Wang <jiong.wang@netronome.com>2019-01-26 12:26:00 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-01-26 16:33:01 -0500
commita72dafafbd5f11c6ea3a9682d64da1074f28eb67 (patch)
treeae346ff4d6db900c334a2a7512165d13880b4954 /kernel
parentd405c7407a5468d4fc11724d76063e0647d80106 (diff)
bpf: refactor verifier min/max code for condition jump
The current min/max code does both signed and unsigned comparisons against the input argument "val" which is "u64" and there is explicit type casting when the comparison is signed. As we will need slightly more complexer type casting when JMP32 introduced, it is better to host the signed type casting. This makes the code more clean with ignorable runtime overhead. Also, code for J*GE/GT/LT/LE and JEQ/JNE are very similar, this patch combine them. The main purpose for this refactor is to make sure the min/max code will still be readable and with minimum code duplication after JMP32 introduced. Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Jiong Wang <jiong.wang@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/verifier.c172
1 files changed, 99 insertions, 73 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 8cfe39ef770f..eae6cb1fe653 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4033,9 +4033,13 @@ static void find_good_pkt_pointers(struct bpf_verifier_state *vstate,
4033 */ 4033 */
4034static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) 4034static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
4035{ 4035{
4036 s64 sval;
4037
4036 if (__is_pointer_value(false, reg)) 4038 if (__is_pointer_value(false, reg))
4037 return -1; 4039 return -1;
4038 4040
4041 sval = (s64)val;
4042
4039 switch (opcode) { 4043 switch (opcode) {
4040 case BPF_JEQ: 4044 case BPF_JEQ:
4041 if (tnum_is_const(reg->var_off)) 4045 if (tnum_is_const(reg->var_off))
@@ -4058,9 +4062,9 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
4058 return 0; 4062 return 0;
4059 break; 4063 break;
4060 case BPF_JSGT: 4064 case BPF_JSGT:
4061 if (reg->smin_value > (s64)val) 4065 if (reg->smin_value > sval)
4062 return 1; 4066 return 1;
4063 else if (reg->smax_value < (s64)val) 4067 else if (reg->smax_value < sval)
4064 return 0; 4068 return 0;
4065 break; 4069 break;
4066 case BPF_JLT: 4070 case BPF_JLT:
@@ -4070,9 +4074,9 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
4070 return 0; 4074 return 0;
4071 break; 4075 break;
4072 case BPF_JSLT: 4076 case BPF_JSLT:
4073 if (reg->smax_value < (s64)val) 4077 if (reg->smax_value < sval)
4074 return 1; 4078 return 1;
4075 else if (reg->smin_value >= (s64)val) 4079 else if (reg->smin_value >= sval)
4076 return 0; 4080 return 0;
4077 break; 4081 break;
4078 case BPF_JGE: 4082 case BPF_JGE:
@@ -4082,9 +4086,9 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
4082 return 0; 4086 return 0;
4083 break; 4087 break;
4084 case BPF_JSGE: 4088 case BPF_JSGE:
4085 if (reg->smin_value >= (s64)val) 4089 if (reg->smin_value >= sval)
4086 return 1; 4090 return 1;
4087 else if (reg->smax_value < (s64)val) 4091 else if (reg->smax_value < sval)
4088 return 0; 4092 return 0;
4089 break; 4093 break;
4090 case BPF_JLE: 4094 case BPF_JLE:
@@ -4094,9 +4098,9 @@ static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode)
4094 return 0; 4098 return 0;
4095 break; 4099 break;
4096 case BPF_JSLE: 4100 case BPF_JSLE:
4097 if (reg->smax_value <= (s64)val) 4101 if (reg->smax_value <= sval)
4098 return 1; 4102 return 1;
4099 else if (reg->smin_value > (s64)val) 4103 else if (reg->smin_value > sval)
4100 return 0; 4104 return 0;
4101 break; 4105 break;
4102 } 4106 }
@@ -4113,6 +4117,8 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
4113 struct bpf_reg_state *false_reg, u64 val, 4117 struct bpf_reg_state *false_reg, u64 val,
4114 u8 opcode) 4118 u8 opcode)
4115{ 4119{
4120 s64 sval;
4121
4116 /* If the dst_reg is a pointer, we can't learn anything about its 4122 /* If the dst_reg is a pointer, we can't learn anything about its
4117 * variable offset from the compare (unless src_reg were a pointer into 4123 * variable offset from the compare (unless src_reg were a pointer into
4118 * the same object, but we don't bother with that. 4124 * the same object, but we don't bother with that.
@@ -4122,19 +4128,22 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
4122 if (__is_pointer_value(false, false_reg)) 4128 if (__is_pointer_value(false, false_reg))
4123 return; 4129 return;
4124 4130
4131 sval = (s64)val;
4132
4125 switch (opcode) { 4133 switch (opcode) {
4126 case BPF_JEQ: 4134 case BPF_JEQ:
4127 /* If this is false then we know nothing Jon Snow, but if it is
4128 * true then we know for sure.
4129 */
4130 __mark_reg_known(true_reg, val);
4131 break;
4132 case BPF_JNE: 4135 case BPF_JNE:
4133 /* If this is true we know nothing Jon Snow, but if it is false 4136 {
4134 * we know the value for sure; 4137 struct bpf_reg_state *reg =
4138 opcode == BPF_JEQ ? true_reg : false_reg;
4139
4140 /* For BPF_JEQ, if this is false we know nothing Jon Snow, but
4141 * if it is true we know the value for sure. Likewise for
4142 * BPF_JNE.
4135 */ 4143 */
4136 __mark_reg_known(false_reg, val); 4144 __mark_reg_known(reg, val);
4137 break; 4145 break;
4146 }
4138 case BPF_JSET: 4147 case BPF_JSET:
4139 false_reg->var_off = tnum_and(false_reg->var_off, 4148 false_reg->var_off = tnum_and(false_reg->var_off,
4140 tnum_const(~val)); 4149 tnum_const(~val));
@@ -4142,38 +4151,46 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
4142 true_reg->var_off = tnum_or(true_reg->var_off, 4151 true_reg->var_off = tnum_or(true_reg->var_off,
4143 tnum_const(val)); 4152 tnum_const(val));
4144 break; 4153 break;
4145 case BPF_JGT:
4146 false_reg->umax_value = min(false_reg->umax_value, val);
4147 true_reg->umin_value = max(true_reg->umin_value, val + 1);
4148 break;
4149 case BPF_JSGT:
4150 false_reg->smax_value = min_t(s64, false_reg->smax_value, val);
4151 true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1);
4152 break;
4153 case BPF_JLT:
4154 false_reg->umin_value = max(false_reg->umin_value, val);
4155 true_reg->umax_value = min(true_reg->umax_value, val - 1);
4156 break;
4157 case BPF_JSLT:
4158 false_reg->smin_value = max_t(s64, false_reg->smin_value, val);
4159 true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1);
4160 break;
4161 case BPF_JGE: 4154 case BPF_JGE:
4162 false_reg->umax_value = min(false_reg->umax_value, val - 1); 4155 case BPF_JGT:
4163 true_reg->umin_value = max(true_reg->umin_value, val); 4156 {
4157 u64 false_umax = opcode == BPF_JGT ? val : val - 1;
4158 u64 true_umin = opcode == BPF_JGT ? val + 1 : val;
4159
4160 false_reg->umax_value = min(false_reg->umax_value, false_umax);
4161 true_reg->umin_value = max(true_reg->umin_value, true_umin);
4164 break; 4162 break;
4163 }
4165 case BPF_JSGE: 4164 case BPF_JSGE:
4166 false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); 4165 case BPF_JSGT:
4167 true_reg->smin_value = max_t(s64, true_reg->smin_value, val); 4166 {
4167 s64 false_smax = opcode == BPF_JSGT ? sval : sval - 1;
4168 s64 true_smin = opcode == BPF_JSGT ? sval + 1 : sval;
4169
4170 false_reg->smax_value = min(false_reg->smax_value, false_smax);
4171 true_reg->smin_value = max(true_reg->smin_value, true_smin);
4168 break; 4172 break;
4173 }
4169 case BPF_JLE: 4174 case BPF_JLE:
4170 false_reg->umin_value = max(false_reg->umin_value, val + 1); 4175 case BPF_JLT:
4171 true_reg->umax_value = min(true_reg->umax_value, val); 4176 {
4177 u64 false_umin = opcode == BPF_JLT ? val : val + 1;
4178 u64 true_umax = opcode == BPF_JLT ? val - 1 : val;
4179
4180 false_reg->umin_value = max(false_reg->umin_value, false_umin);
4181 true_reg->umax_value = min(true_reg->umax_value, true_umax);
4172 break; 4182 break;
4183 }
4173 case BPF_JSLE: 4184 case BPF_JSLE:
4174 false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); 4185 case BPF_JSLT:
4175 true_reg->smax_value = min_t(s64, true_reg->smax_value, val); 4186 {
4187 s64 false_smin = opcode == BPF_JSLT ? sval : sval + 1;
4188 s64 true_smax = opcode == BPF_JSLT ? sval - 1 : sval;
4189
4190 false_reg->smin_value = max(false_reg->smin_value, false_smin);
4191 true_reg->smax_value = min(true_reg->smax_value, true_smax);
4176 break; 4192 break;
4193 }
4177 default: 4194 default:
4178 break; 4195 break;
4179 } 4196 }
@@ -4198,22 +4215,23 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
4198 struct bpf_reg_state *false_reg, u64 val, 4215 struct bpf_reg_state *false_reg, u64 val,
4199 u8 opcode) 4216 u8 opcode)
4200{ 4217{
4218 s64 sval;
4219
4201 if (__is_pointer_value(false, false_reg)) 4220 if (__is_pointer_value(false, false_reg))
4202 return; 4221 return;
4203 4222
4223 sval = (s64)val;
4224
4204 switch (opcode) { 4225 switch (opcode) {
4205 case BPF_JEQ: 4226 case BPF_JEQ:
4206 /* If this is false then we know nothing Jon Snow, but if it is
4207 * true then we know for sure.
4208 */
4209 __mark_reg_known(true_reg, val);
4210 break;
4211 case BPF_JNE: 4227 case BPF_JNE:
4212 /* If this is true we know nothing Jon Snow, but if it is false 4228 {
4213 * we know the value for sure; 4229 struct bpf_reg_state *reg =
4214 */ 4230 opcode == BPF_JEQ ? true_reg : false_reg;
4215 __mark_reg_known(false_reg, val); 4231
4232 __mark_reg_known(reg, val);
4216 break; 4233 break;
4234 }
4217 case BPF_JSET: 4235 case BPF_JSET:
4218 false_reg->var_off = tnum_and(false_reg->var_off, 4236 false_reg->var_off = tnum_and(false_reg->var_off,
4219 tnum_const(~val)); 4237 tnum_const(~val));
@@ -4221,38 +4239,46 @@ static void reg_set_min_max_inv(struct bpf_reg_state *true_reg,
4221 true_reg->var_off = tnum_or(true_reg->var_off, 4239 true_reg->var_off = tnum_or(true_reg->var_off,
4222 tnum_const(val)); 4240 tnum_const(val));
4223 break; 4241 break;
4224 case BPF_JGT:
4225 true_reg->umax_value = min(true_reg->umax_value, val - 1);
4226 false_reg->umin_value = max(false_reg->umin_value, val);
4227 break;
4228 case BPF_JSGT:
4229 true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1);
4230 false_reg->smin_value = max_t(s64, false_reg->smin_value, val);
4231 break;
4232 case BPF_JLT:
4233 true_reg->umin_value = max(true_reg->umin_value, val + 1);
4234 false_reg->umax_value = min(false_reg->umax_value, val);
4235 break;
4236 case BPF_JSLT:
4237 true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1);
4238 false_reg->smax_value = min_t(s64, false_reg->smax_value, val);
4239 break;
4240 case BPF_JGE: 4242 case BPF_JGE:
4241 true_reg->umax_value = min(true_reg->umax_value, val); 4243 case BPF_JGT:
4242 false_reg->umin_value = max(false_reg->umin_value, val + 1); 4244 {
4245 u64 false_umin = opcode == BPF_JGT ? val : val + 1;
4246 u64 true_umax = opcode == BPF_JGT ? val - 1 : val;
4247
4248 false_reg->umin_value = max(false_reg->umin_value, false_umin);
4249 true_reg->umax_value = min(true_reg->umax_value, true_umax);
4243 break; 4250 break;
4251 }
4244 case BPF_JSGE: 4252 case BPF_JSGE:
4245 true_reg->smax_value = min_t(s64, true_reg->smax_value, val); 4253 case BPF_JSGT:
4246 false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); 4254 {
4255 s64 false_smin = opcode == BPF_JSGT ? sval : sval + 1;
4256 s64 true_smax = opcode == BPF_JSGT ? sval - 1 : sval;
4257
4258 false_reg->smin_value = max(false_reg->smin_value, false_smin);
4259 true_reg->smax_value = min(true_reg->smax_value, true_smax);
4247 break; 4260 break;
4261 }
4248 case BPF_JLE: 4262 case BPF_JLE:
4249 true_reg->umin_value = max(true_reg->umin_value, val); 4263 case BPF_JLT:
4250 false_reg->umax_value = min(false_reg->umax_value, val - 1); 4264 {
4265 u64 false_umax = opcode == BPF_JLT ? val : val - 1;
4266 u64 true_umin = opcode == BPF_JLT ? val + 1 : val;
4267
4268 false_reg->umax_value = min(false_reg->umax_value, false_umax);
4269 true_reg->umin_value = max(true_reg->umin_value, true_umin);
4251 break; 4270 break;
4271 }
4252 case BPF_JSLE: 4272 case BPF_JSLE:
4253 true_reg->smin_value = max_t(s64, true_reg->smin_value, val); 4273 case BPF_JSLT:
4254 false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); 4274 {
4275 s64 false_smax = opcode == BPF_JSLT ? sval : sval - 1;
4276 s64 true_smin = opcode == BPF_JSLT ? sval + 1 : sval;
4277
4278 false_reg->smax_value = min(false_reg->smax_value, false_smax);
4279 true_reg->smin_value = max(true_reg->smin_value, true_smin);
4255 break; 4280 break;
4281 }
4256 default: 4282 default:
4257 break; 4283 break;
4258 } 4284 }