diff options
Diffstat (limited to 'kernel')
| -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 | } |
