diff options
-rw-r--r-- | include/linux/bpf_verifier.h | 1 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 74 |
2 files changed, 70 insertions, 5 deletions
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index c736945be7c5..548dcbdb7111 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h | |||
@@ -224,6 +224,7 @@ struct bpf_verifier_env { | |||
224 | bool allow_ptr_leaks; | 224 | bool allow_ptr_leaks; |
225 | bool seen_direct_write; | 225 | bool seen_direct_write; |
226 | struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ | 226 | struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ |
227 | const struct bpf_line_info *prev_linfo; | ||
227 | struct bpf_verifier_log log; | 228 | struct bpf_verifier_log log; |
228 | struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; | 229 | struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; |
229 | u32 subprog_cnt; | 230 | u32 subprog_cnt; |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 89ce2613fdb0..ba8e3134bbc2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/bsearch.h> | 26 | #include <linux/bsearch.h> |
27 | #include <linux/sort.h> | 27 | #include <linux/sort.h> |
28 | #include <linux/perf_event.h> | 28 | #include <linux/perf_event.h> |
29 | #include <linux/ctype.h> | ||
29 | 30 | ||
30 | #include "disasm.h" | 31 | #include "disasm.h" |
31 | 32 | ||
@@ -216,6 +217,27 @@ struct bpf_call_arg_meta { | |||
216 | 217 | ||
217 | static DEFINE_MUTEX(bpf_verifier_lock); | 218 | static DEFINE_MUTEX(bpf_verifier_lock); |
218 | 219 | ||
220 | static const struct bpf_line_info * | ||
221 | find_linfo(const struct bpf_verifier_env *env, u32 insn_off) | ||
222 | { | ||
223 | const struct bpf_line_info *linfo; | ||
224 | const struct bpf_prog *prog; | ||
225 | u32 i, nr_linfo; | ||
226 | |||
227 | prog = env->prog; | ||
228 | nr_linfo = prog->aux->nr_linfo; | ||
229 | |||
230 | if (!nr_linfo || insn_off >= prog->len) | ||
231 | return NULL; | ||
232 | |||
233 | linfo = prog->aux->linfo; | ||
234 | for (i = 1; i < nr_linfo; i++) | ||
235 | if (insn_off < linfo[i].insn_off) | ||
236 | break; | ||
237 | |||
238 | return &linfo[i - 1]; | ||
239 | } | ||
240 | |||
219 | void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, | 241 | void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, |
220 | va_list args) | 242 | va_list args) |
221 | { | 243 | { |
@@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) | |||
266 | va_end(args); | 288 | va_end(args); |
267 | } | 289 | } |
268 | 290 | ||
291 | static const char *ltrim(const char *s) | ||
292 | { | ||
293 | while (isspace(*s)) | ||
294 | s++; | ||
295 | |||
296 | return s; | ||
297 | } | ||
298 | |||
299 | __printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env, | ||
300 | u32 insn_off, | ||
301 | const char *prefix_fmt, ...) | ||
302 | { | ||
303 | const struct bpf_line_info *linfo; | ||
304 | |||
305 | if (!bpf_verifier_log_needed(&env->log)) | ||
306 | return; | ||
307 | |||
308 | linfo = find_linfo(env, insn_off); | ||
309 | if (!linfo || linfo == env->prev_linfo) | ||
310 | return; | ||
311 | |||
312 | if (prefix_fmt) { | ||
313 | va_list args; | ||
314 | |||
315 | va_start(args, prefix_fmt); | ||
316 | bpf_verifier_vlog(&env->log, prefix_fmt, args); | ||
317 | va_end(args); | ||
318 | } | ||
319 | |||
320 | verbose(env, "%s\n", | ||
321 | ltrim(btf_name_by_offset(env->prog->aux->btf, | ||
322 | linfo->line_off))); | ||
323 | |||
324 | env->prev_linfo = linfo; | ||
325 | } | ||
326 | |||
269 | static bool type_is_pkt_pointer(enum bpf_reg_type type) | 327 | static bool type_is_pkt_pointer(enum bpf_reg_type type) |
270 | { | 328 | { |
271 | return type == PTR_TO_PACKET || | 329 | return type == PTR_TO_PACKET || |
@@ -4561,6 +4619,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env) | |||
4561 | return 0; | 4619 | return 0; |
4562 | 4620 | ||
4563 | if (w < 0 || w >= env->prog->len) { | 4621 | if (w < 0 || w >= env->prog->len) { |
4622 | verbose_linfo(env, t, "%d: ", t); | ||
4564 | verbose(env, "jump out of range from insn %d to %d\n", t, w); | 4623 | verbose(env, "jump out of range from insn %d to %d\n", t, w); |
4565 | return -EINVAL; | 4624 | return -EINVAL; |
4566 | } | 4625 | } |
@@ -4578,6 +4637,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env) | |||
4578 | insn_stack[cur_stack++] = w; | 4637 | insn_stack[cur_stack++] = w; |
4579 | return 1; | 4638 | return 1; |
4580 | } else if ((insn_state[w] & 0xF0) == DISCOVERED) { | 4639 | } else if ((insn_state[w] & 0xF0) == DISCOVERED) { |
4640 | verbose_linfo(env, t, "%d: ", t); | ||
4641 | verbose_linfo(env, w, "%d: ", w); | ||
4581 | verbose(env, "back-edge from insn %d to %d\n", t, w); | 4642 | verbose(env, "back-edge from insn %d to %d\n", t, w); |
4582 | return -EINVAL; | 4643 | return -EINVAL; |
4583 | } else if (insn_state[w] == EXPLORED) { | 4644 | } else if (insn_state[w] == EXPLORED) { |
@@ -4600,10 +4661,6 @@ static int check_cfg(struct bpf_verifier_env *env) | |||
4600 | int ret = 0; | 4661 | int ret = 0; |
4601 | int i, t; | 4662 | int i, t; |
4602 | 4663 | ||
4603 | ret = check_subprogs(env); | ||
4604 | if (ret < 0) | ||
4605 | return ret; | ||
4606 | |||
4607 | insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); | 4664 | insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); |
4608 | if (!insn_state) | 4665 | if (!insn_state) |
4609 | return -ENOMEM; | 4666 | return -ENOMEM; |
@@ -5448,6 +5505,8 @@ static int do_check(struct bpf_verifier_env *env) | |||
5448 | int insn_processed = 0; | 5505 | int insn_processed = 0; |
5449 | bool do_print_state = false; | 5506 | bool do_print_state = false; |
5450 | 5507 | ||
5508 | env->prev_linfo = NULL; | ||
5509 | |||
5451 | state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); | 5510 | state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); |
5452 | if (!state) | 5511 | if (!state) |
5453 | return -ENOMEM; | 5512 | return -ENOMEM; |
@@ -5521,6 +5580,7 @@ static int do_check(struct bpf_verifier_env *env) | |||
5521 | .private_data = env, | 5580 | .private_data = env, |
5522 | }; | 5581 | }; |
5523 | 5582 | ||
5583 | verbose_linfo(env, insn_idx, "; "); | ||
5524 | verbose(env, "%d: ", insn_idx); | 5584 | verbose(env, "%d: ", insn_idx); |
5525 | print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); | 5585 | print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); |
5526 | } | 5586 | } |
@@ -6755,7 +6815,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, | |||
6755 | 6815 | ||
6756 | env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); | 6816 | env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); |
6757 | 6817 | ||
6758 | ret = check_cfg(env); | 6818 | ret = check_subprogs(env); |
6759 | if (ret < 0) | 6819 | if (ret < 0) |
6760 | goto skip_full_check; | 6820 | goto skip_full_check; |
6761 | 6821 | ||
@@ -6763,6 +6823,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, | |||
6763 | if (ret < 0) | 6823 | if (ret < 0) |
6764 | goto skip_full_check; | 6824 | goto skip_full_check; |
6765 | 6825 | ||
6826 | ret = check_cfg(env); | ||
6827 | if (ret < 0) | ||
6828 | goto skip_full_check; | ||
6829 | |||
6766 | ret = do_check(env); | 6830 | ret = do_check(env); |
6767 | if (env->cur_state) { | 6831 | if (env->cur_state) { |
6768 | free_verifier_state(env->cur_state, true); | 6832 | free_verifier_state(env->cur_state, true); |