Commit e7bf8249 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

bpf: encapsulate verifier log state into a structure

Put the loose log_* variables into a structure.  This will make
it simpler to remove the global verifier state in following patches.
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a99ca6db
...@@ -115,6 +115,19 @@ struct bpf_insn_aux_data { ...@@ -115,6 +115,19 @@ struct bpf_insn_aux_data {
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */ #define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
struct bpf_verifer_log {
u32 level;
char *kbuf;
char __user *ubuf;
u32 len_used;
u32 len_total;
};
static inline bool bpf_verifier_log_full(const struct bpf_verifer_log *log)
{
return log->len_used >= log->len_total - 1;
}
struct bpf_verifier_env; struct bpf_verifier_env;
struct bpf_ext_analyzer_ops { struct bpf_ext_analyzer_ops {
int (*insn_hook)(struct bpf_verifier_env *env, int (*insn_hook)(struct bpf_verifier_env *env,
......
...@@ -156,8 +156,7 @@ struct bpf_call_arg_meta { ...@@ -156,8 +156,7 @@ struct bpf_call_arg_meta {
/* verbose verifier prints what it's seeing /* verbose verifier prints what it's seeing
* bpf_check() is called under lock, so no race to access these global vars * bpf_check() is called under lock, so no race to access these global vars
*/ */
static u32 log_level, log_size, log_len; static struct bpf_verifer_log verifier_log;
static char *log_buf;
static DEFINE_MUTEX(bpf_verifier_lock); static DEFINE_MUTEX(bpf_verifier_lock);
...@@ -167,13 +166,15 @@ static DEFINE_MUTEX(bpf_verifier_lock); ...@@ -167,13 +166,15 @@ static DEFINE_MUTEX(bpf_verifier_lock);
*/ */
static __printf(1, 2) void verbose(const char *fmt, ...) static __printf(1, 2) void verbose(const char *fmt, ...)
{ {
struct bpf_verifer_log *log = &verifier_log;
va_list args; va_list args;
if (log_level == 0 || log_len >= log_size - 1) if (!log->level || bpf_verifier_log_full(log))
return; return;
va_start(args, fmt); va_start(args, fmt);
log_len += vscnprintf(log_buf + log_len, log_size - log_len, fmt, args); log->len_used += vscnprintf(log->kbuf + log->len_used,
log->len_total - log->len_used, fmt, args);
va_end(args); va_end(args);
} }
...@@ -886,7 +887,7 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, ...@@ -886,7 +887,7 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno,
* need to try adding each of min_value and max_value to off * need to try adding each of min_value and max_value to off
* to make sure our theoretical access will be safe. * to make sure our theoretical access will be safe.
*/ */
if (log_level) if (verifier_log.level)
print_verifier_state(state); print_verifier_state(state);
/* The minimum value is only important with signed /* The minimum value is only important with signed
* comparisons where we can't assume the floor of a * comparisons where we can't assume the floor of a
...@@ -2956,7 +2957,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env, ...@@ -2956,7 +2957,7 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
verbose("R%d pointer comparison prohibited\n", insn->dst_reg); verbose("R%d pointer comparison prohibited\n", insn->dst_reg);
return -EACCES; return -EACCES;
} }
if (log_level) if (verifier_log.level)
print_verifier_state(this_branch); print_verifier_state(this_branch);
return 0; return 0;
} }
...@@ -3712,7 +3713,7 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -3712,7 +3713,7 @@ static int do_check(struct bpf_verifier_env *env)
return err; return err;
if (err == 1) { if (err == 1) {
/* found equivalent state, can prune the search */ /* found equivalent state, can prune the search */
if (log_level) { if (verifier_log.level) {
if (do_print_state) if (do_print_state)
verbose("\nfrom %d to %d: safe\n", verbose("\nfrom %d to %d: safe\n",
prev_insn_idx, insn_idx); prev_insn_idx, insn_idx);
...@@ -3725,8 +3726,9 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -3725,8 +3726,9 @@ static int do_check(struct bpf_verifier_env *env)
if (need_resched()) if (need_resched())
cond_resched(); cond_resched();
if (log_level > 1 || (log_level && do_print_state)) { if (verifier_log.level > 1 ||
if (log_level > 1) (verifier_log.level && do_print_state)) {
if (verifier_log.level > 1)
verbose("%d:", insn_idx); verbose("%d:", insn_idx);
else else
verbose("\nfrom %d to %d:", verbose("\nfrom %d to %d:",
...@@ -3735,7 +3737,7 @@ static int do_check(struct bpf_verifier_env *env) ...@@ -3735,7 +3737,7 @@ static int do_check(struct bpf_verifier_env *env)
do_print_state = false; do_print_state = false;
} }
if (log_level) { if (verifier_log.level) {
verbose("%d: ", insn_idx); verbose("%d: ", insn_idx);
print_bpf_insn(env, insn); print_bpf_insn(env, insn);
} }
...@@ -4389,7 +4391,7 @@ static void free_states(struct bpf_verifier_env *env) ...@@ -4389,7 +4391,7 @@ static void free_states(struct bpf_verifier_env *env)
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
{ {
char __user *log_ubuf = NULL; struct bpf_verifer_log *log = &verifier_log;
struct bpf_verifier_env *env; struct bpf_verifier_env *env;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -4414,23 +4416,23 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4414,23 +4416,23 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
/* user requested verbose verifier output /* user requested verbose verifier output
* and supplied buffer to store the verification trace * and supplied buffer to store the verification trace
*/ */
log_level = attr->log_level; log->level = attr->log_level;
log_ubuf = (char __user *) (unsigned long) attr->log_buf; log->ubuf = (char __user *) (unsigned long) attr->log_buf;
log_size = attr->log_size; log->len_total = attr->log_size;
log_len = 0; log->len_used = 0;
ret = -EINVAL; ret = -EINVAL;
/* log_* values have to be sane */ /* log attributes have to be sane */
if (log_size < 128 || log_size > UINT_MAX >> 8 || if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 ||
log_level == 0 || log_ubuf == NULL) !log->level || !log->ubuf)
goto err_unlock; goto err_unlock;
ret = -ENOMEM; ret = -ENOMEM;
log_buf = vmalloc(log_size); log->kbuf = vmalloc(log->len_total);
if (!log_buf) if (!log->kbuf)
goto err_unlock; goto err_unlock;
} else { } else {
log_level = 0; log->level = 0;
} }
env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT); env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
...@@ -4467,15 +4469,16 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4467,15 +4469,16 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
if (ret == 0) if (ret == 0)
ret = fixup_bpf_calls(env); ret = fixup_bpf_calls(env);
if (log_level && log_len >= log_size - 1) { if (log->level && bpf_verifier_log_full(log)) {
BUG_ON(log_len >= log_size); BUG_ON(log->len_used >= log->len_total);
/* verifier log exceeded user supplied buffer */ /* verifier log exceeded user supplied buffer */
ret = -ENOSPC; ret = -ENOSPC;
/* fall through to return what was recorded */ /* fall through to return what was recorded */
} }
/* copy verifier log back to user space including trailing zero */ /* copy verifier log back to user space including trailing zero */
if (log_level && copy_to_user(log_ubuf, log_buf, log_len + 1) != 0) { if (log->level && copy_to_user(log->ubuf, log->kbuf,
log->len_used + 1) != 0) {
ret = -EFAULT; ret = -EFAULT;
goto free_log_buf; goto free_log_buf;
} }
...@@ -4502,8 +4505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4502,8 +4505,8 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
} }
free_log_buf: free_log_buf:
if (log_level) if (log->level)
vfree(log_buf); vfree(log->kbuf);
if (!env->prog->aux->used_maps) if (!env->prog->aux->used_maps)
/* if we didn't copy map pointers into bpf_prog_info, release /* if we didn't copy map pointers into bpf_prog_info, release
* them now. Otherwise free_bpf_prog_info() will release them. * them now. Otherwise free_bpf_prog_info() will release them.
...@@ -4540,7 +4543,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops, ...@@ -4540,7 +4543,7 @@ int bpf_analyzer(struct bpf_prog *prog, const struct bpf_ext_analyzer_ops *ops,
/* grab the mutex to protect few globals used by verifier */ /* grab the mutex to protect few globals used by verifier */
mutex_lock(&bpf_verifier_lock); mutex_lock(&bpf_verifier_lock);
log_level = 0; verifier_log.level = 0;
env->strict_alignment = false; env->strict_alignment = false;
if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
......
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