aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/bpf_verifier.h1
-rw-r--r--kernel/bpf/verifier.c74
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
217static DEFINE_MUTEX(bpf_verifier_lock); 218static DEFINE_MUTEX(bpf_verifier_lock);
218 219
220static const struct bpf_line_info *
221find_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
219void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, 241void 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
291static 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
269static bool type_is_pkt_pointer(enum bpf_reg_type type) 327static 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);