Commit eb415c98 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'bpf_line_info-in-verifier'

Martin Lau says:

====================
This patch set provides bpf_line_info during the verifier's verbose
log.  Please see individual patch for details.
====================
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 28c12729 d9762e84
...@@ -224,6 +224,7 @@ struct bpf_verifier_env { ...@@ -224,6 +224,7 @@ struct bpf_verifier_env {
bool allow_ptr_leaks; bool allow_ptr_leaks;
bool seen_direct_write; bool seen_direct_write;
struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */ struct bpf_insn_aux_data *insn_aux_data; /* array of per-insn state */
const struct bpf_line_info *prev_linfo;
struct bpf_verifier_log log; struct bpf_verifier_log log;
struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1]; struct bpf_subprog_info subprog_info[BPF_MAX_SUBPROGS + 1];
u32 subprog_cnt; u32 subprog_cnt;
......
...@@ -46,7 +46,6 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj, ...@@ -46,7 +46,6 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj,
struct seq_file *m); struct seq_file *m);
int btf_get_fd_by_id(u32 id); int btf_get_fd_by_id(u32 id);
u32 btf_id(const struct btf *btf); u32 btf_id(const struct btf *btf);
bool btf_name_offset_valid(const struct btf *btf, u32 offset);
bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size); bool btf_type_is_reg_int(const struct btf_type *t, u32 expected_size);
#ifdef CONFIG_BPF_SYSCALL #ifdef CONFIG_BPF_SYSCALL
......
...@@ -474,7 +474,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset) ...@@ -474,7 +474,7 @@ static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
return !*src; return !*src;
} }
const char *btf_name_by_offset(const struct btf *btf, u32 offset) static const char *__btf_name_by_offset(const struct btf *btf, u32 offset)
{ {
if (!offset) if (!offset)
return "(anon)"; return "(anon)";
...@@ -484,6 +484,14 @@ const char *btf_name_by_offset(const struct btf *btf, u32 offset) ...@@ -484,6 +484,14 @@ const char *btf_name_by_offset(const struct btf *btf, u32 offset)
return "(invalid-name-offset)"; return "(invalid-name-offset)";
} }
const char *btf_name_by_offset(const struct btf *btf, u32 offset)
{
if (offset < btf->hdr.str_len)
return &btf->strings[offset];
return NULL;
}
const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
{ {
if (type_id > btf->nr_types) if (type_id > btf->nr_types)
...@@ -576,7 +584,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env, ...@@ -576,7 +584,7 @@ __printf(4, 5) static void __btf_verifier_log_type(struct btf_verifier_env *env,
__btf_verifier_log(log, "[%u] %s %s%s", __btf_verifier_log(log, "[%u] %s %s%s",
env->log_type_id, env->log_type_id,
btf_kind_str[kind], btf_kind_str[kind],
btf_name_by_offset(btf, t->name_off), __btf_name_by_offset(btf, t->name_off),
log_details ? " " : ""); log_details ? " " : "");
if (log_details) if (log_details)
...@@ -620,7 +628,7 @@ static void btf_verifier_log_member(struct btf_verifier_env *env, ...@@ -620,7 +628,7 @@ static void btf_verifier_log_member(struct btf_verifier_env *env,
btf_verifier_log_type(env, struct_type, NULL); btf_verifier_log_type(env, struct_type, NULL);
__btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u", __btf_verifier_log(log, "\t%s type_id=%u bits_offset=%u",
btf_name_by_offset(btf, member->name_off), __btf_name_by_offset(btf, member->name_off),
member->type, member->offset); member->type, member->offset);
if (fmt && *fmt) { if (fmt && *fmt) {
...@@ -1872,7 +1880,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env, ...@@ -1872,7 +1880,7 @@ static s32 btf_enum_check_meta(struct btf_verifier_env *env,
btf_verifier_log(env, "\t%s val=%d\n", btf_verifier_log(env, "\t%s val=%d\n",
btf_name_by_offset(btf, enums[i].name_off), __btf_name_by_offset(btf, enums[i].name_off),
enums[i].val); enums[i].val);
} }
...@@ -1896,7 +1904,8 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t, ...@@ -1896,7 +1904,8 @@ static void btf_enum_seq_show(const struct btf *btf, const struct btf_type *t,
for (i = 0; i < nr_enums; i++) { for (i = 0; i < nr_enums; i++) {
if (v == enums[i].val) { if (v == enums[i].val) {
seq_printf(m, "%s", seq_printf(m, "%s",
btf_name_by_offset(btf, enums[i].name_off)); __btf_name_by_offset(btf,
enums[i].name_off));
return; return;
} }
} }
...@@ -1954,11 +1963,11 @@ static void btf_func_proto_log(struct btf_verifier_env *env, ...@@ -1954,11 +1963,11 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
} }
btf_verifier_log(env, "%u %s", args[0].type, btf_verifier_log(env, "%u %s", args[0].type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
args[0].name_off)); args[0].name_off));
for (i = 1; i < nr_args - 1; i++) for (i = 1; i < nr_args - 1; i++)
btf_verifier_log(env, ", %u %s", args[i].type, btf_verifier_log(env, ", %u %s", args[i].type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
args[i].name_off)); args[i].name_off));
if (nr_args > 1) { if (nr_args > 1) {
...@@ -1966,7 +1975,7 @@ static void btf_func_proto_log(struct btf_verifier_env *env, ...@@ -1966,7 +1975,7 @@ static void btf_func_proto_log(struct btf_verifier_env *env,
if (last_arg->type) if (last_arg->type)
btf_verifier_log(env, ", %u %s", last_arg->type, btf_verifier_log(env, ", %u %s", last_arg->type,
btf_name_by_offset(env->btf, __btf_name_by_offset(env->btf,
last_arg->name_off)); last_arg->name_off));
else else
btf_verifier_log(env, ", vararg"); btf_verifier_log(env, ", vararg");
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/bsearch.h> #include <linux/bsearch.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <linux/ctype.h>
#include "disasm.h" #include "disasm.h"
...@@ -216,6 +217,27 @@ struct bpf_call_arg_meta { ...@@ -216,6 +217,27 @@ struct bpf_call_arg_meta {
static DEFINE_MUTEX(bpf_verifier_lock); static DEFINE_MUTEX(bpf_verifier_lock);
static const struct bpf_line_info *
find_linfo(const struct bpf_verifier_env *env, u32 insn_off)
{
const struct bpf_line_info *linfo;
const struct bpf_prog *prog;
u32 i, nr_linfo;
prog = env->prog;
nr_linfo = prog->aux->nr_linfo;
if (!nr_linfo || insn_off >= prog->len)
return NULL;
linfo = prog->aux->linfo;
for (i = 1; i < nr_linfo; i++)
if (insn_off < linfo[i].insn_off)
break;
return &linfo[i - 1];
}
void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt, void bpf_verifier_vlog(struct bpf_verifier_log *log, const char *fmt,
va_list args) va_list args)
{ {
...@@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) ...@@ -266,6 +288,42 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
va_end(args); va_end(args);
} }
static const char *ltrim(const char *s)
{
while (isspace(*s))
s++;
return s;
}
__printf(3, 4) static void verbose_linfo(struct bpf_verifier_env *env,
u32 insn_off,
const char *prefix_fmt, ...)
{
const struct bpf_line_info *linfo;
if (!bpf_verifier_log_needed(&env->log))
return;
linfo = find_linfo(env, insn_off);
if (!linfo || linfo == env->prev_linfo)
return;
if (prefix_fmt) {
va_list args;
va_start(args, prefix_fmt);
bpf_verifier_vlog(&env->log, prefix_fmt, args);
va_end(args);
}
verbose(env, "%s\n",
ltrim(btf_name_by_offset(env->prog->aux->btf,
linfo->line_off)));
env->prev_linfo = linfo;
}
static bool type_is_pkt_pointer(enum bpf_reg_type type) static bool type_is_pkt_pointer(enum bpf_reg_type type)
{ {
return type == PTR_TO_PACKET || 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,6 +4619,7 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
return 0; return 0;
if (w < 0 || w >= env->prog->len) { if (w < 0 || w >= env->prog->len) {
verbose_linfo(env, t, "%d: ", t);
verbose(env, "jump out of range from insn %d to %d\n", t, w); verbose(env, "jump out of range from insn %d to %d\n", t, w);
return -EINVAL; return -EINVAL;
} }
...@@ -4578,6 +4637,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env) ...@@ -4578,6 +4637,8 @@ static int push_insn(int t, int w, int e, struct bpf_verifier_env *env)
insn_stack[cur_stack++] = w; insn_stack[cur_stack++] = w;
return 1; return 1;
} else if ((insn_state[w] & 0xF0) == DISCOVERED) { } else if ((insn_state[w] & 0xF0) == DISCOVERED) {
verbose_linfo(env, t, "%d: ", t);
verbose_linfo(env, w, "%d: ", w);
verbose(env, "back-edge from insn %d to %d\n", t, w); verbose(env, "back-edge from insn %d to %d\n", t, w);
return -EINVAL; return -EINVAL;
} else if (insn_state[w] == EXPLORED) { } else if (insn_state[w] == EXPLORED) {
...@@ -4600,10 +4661,6 @@ static int check_cfg(struct bpf_verifier_env *env) ...@@ -4600,10 +4661,6 @@ static int check_cfg(struct bpf_verifier_env *env)
int ret = 0; int ret = 0;
int i, t; int i, t;
ret = check_subprogs(env);
if (ret < 0)
return ret;
insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL); insn_state = kcalloc(insn_cnt, sizeof(int), GFP_KERNEL);
if (!insn_state) if (!insn_state)
return -ENOMEM; return -ENOMEM;
...@@ -4910,8 +4967,8 @@ static int check_btf_line(struct bpf_verifier_env *env, ...@@ -4910,8 +4967,8 @@ static int check_btf_line(struct bpf_verifier_env *env,
goto err_free; goto err_free;
} }
if (!btf_name_offset_valid(btf, linfo[i].line_off) || if (!btf_name_by_offset(btf, linfo[i].line_off) ||
!btf_name_offset_valid(btf, linfo[i].file_name_off)) { !btf_name_by_offset(btf, linfo[i].file_name_off)) {
verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i); verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i);
err = -EINVAL; err = -EINVAL;
goto err_free; goto err_free;
...@@ -5448,6 +5505,8 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -5448,6 +5505,8 @@ static int do_check(struct bpf_verifier_env *env)
int insn_processed = 0; int insn_processed = 0;
bool do_print_state = false; bool do_print_state = false;
env->prev_linfo = NULL;
state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL); state = kzalloc(sizeof(struct bpf_verifier_state), GFP_KERNEL);
if (!state) if (!state)
return -ENOMEM; return -ENOMEM;
...@@ -5521,6 +5580,7 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -5521,6 +5580,7 @@ static int do_check(struct bpf_verifier_env *env)
.private_data = env, .private_data = env,
}; };
verbose_linfo(env, insn_idx, "; ");
verbose(env, "%d: ", insn_idx); verbose(env, "%d: ", insn_idx);
print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); print_bpf_insn(&cbs, insn, env->allow_ptr_leaks);
} }
...@@ -6755,7 +6815,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, ...@@ -6755,7 +6815,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
env->allow_ptr_leaks = capable(CAP_SYS_ADMIN); env->allow_ptr_leaks = capable(CAP_SYS_ADMIN);
ret = check_cfg(env); ret = check_subprogs(env);
if (ret < 0) if (ret < 0)
goto skip_full_check; goto skip_full_check;
...@@ -6763,6 +6823,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, ...@@ -6763,6 +6823,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
if (ret < 0) if (ret < 0)
goto skip_full_check; goto skip_full_check;
ret = check_cfg(env);
if (ret < 0)
goto skip_full_check;
ret = do_check(env); ret = do_check(env);
if (env->cur_state) { if (env->cur_state) {
free_verifier_state(env->cur_state, true); free_verifier_state(env->cur_state, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment