diff options
-rw-r--r-- | kernel/bpf/verifier.c | 172 |
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 | */ |
4034 | static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) | 4034 | static 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 | } |