提交 a2a7d570 编写于 作者: J Jakub Kicinski 提交者: David S. Miller

bpf: write back the verifier log buffer as it gets filled

Verifier log buffer can be quite large (up to 16MB currently).
As Eric Dumazet points out if we allow multiple verification
requests to proceed simultaneously, malicious user may use the
verifier as a way of allocating large amounts of unswappable
memory to OOM the host.

Switch to a strategy of allocating a smaller buffer (1024B)
and writing it out into the user buffer after every print.

While at it remove the old BUG_ON().

This is in preparation of the global verifier lock removal.
Signed-off-by: NJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: NSimon Horman <simon.horman@netronome.com>
Acked-by: NAlexei Starovoitov <ast@kernel.org>
Acked-by: NDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 d66f2b91
...@@ -115,9 +115,11 @@ struct bpf_insn_aux_data { ...@@ -115,9 +115,11 @@ 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 */
#define BPF_VERIFIER_TMP_LOG_SIZE 1024
struct bpf_verifer_log { struct bpf_verifer_log {
u32 level; u32 level;
char *kbuf; char kbuf[BPF_VERIFIER_TMP_LOG_SIZE];
char __user *ubuf; char __user *ubuf;
u32 len_used; u32 len_used;
u32 len_total; u32 len_total;
......
...@@ -165,15 +165,26 @@ static __printf(2, 3) void verbose(struct bpf_verifier_env *env, ...@@ -165,15 +165,26 @@ static __printf(2, 3) void verbose(struct bpf_verifier_env *env,
const char *fmt, ...) const char *fmt, ...)
{ {
struct bpf_verifer_log *log = &env->log; struct bpf_verifer_log *log = &env->log;
unsigned int n;
va_list args; va_list args;
if (!log->level || bpf_verifier_log_full(log)) if (!log->level || !log->ubuf || bpf_verifier_log_full(log))
return; return;
va_start(args, fmt); va_start(args, fmt);
log->len_used += vscnprintf(log->kbuf + log->len_used, n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args);
log->len_total - log->len_used, fmt, args);
va_end(args); va_end(args);
WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1,
"verifier log line truncated - local buffer too short\n");
n = min(log->len_total - log->len_used - 1, n);
log->kbuf[n] = '\0';
if (!copy_to_user(log->ubuf + log->len_used, log->kbuf, n + 1))
log->len_used += n;
else
log->ubuf = NULL;
} }
static bool type_is_pkt_pointer(enum bpf_reg_type type) static bool type_is_pkt_pointer(enum bpf_reg_type type)
...@@ -4263,11 +4274,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4263,11 +4274,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 || if (log->len_total < 128 || log->len_total > UINT_MAX >> 8 ||
!log->level || !log->ubuf) !log->level || !log->ubuf)
goto err_unlock; goto err_unlock;
ret = -ENOMEM;
log->kbuf = vmalloc(log->len_total);
if (!log->kbuf)
goto err_unlock;
} }
env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT); env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);
...@@ -4304,18 +4310,11 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4304,18 +4310,11 @@ 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 && bpf_verifier_log_full(log)) { if (log->level && bpf_verifier_log_full(log))
BUG_ON(log->len_used >= log->len_total);
/* verifier log exceeded user supplied buffer */
ret = -ENOSPC; ret = -ENOSPC;
/* fall through to return what was recorded */ if (log->level && !log->ubuf) {
}
/* copy verifier log back to user space including trailing zero */
if (log->level && copy_to_user(log->ubuf, log->kbuf,
log->len_used + 1) != 0) {
ret = -EFAULT; ret = -EFAULT;
goto free_log_buf; goto err_release_maps;
} }
if (ret == 0 && env->used_map_cnt) { if (ret == 0 && env->used_map_cnt) {
...@@ -4326,7 +4325,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4326,7 +4325,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
if (!env->prog->aux->used_maps) { if (!env->prog->aux->used_maps) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_log_buf; goto err_release_maps;
} }
memcpy(env->prog->aux->used_maps, env->used_maps, memcpy(env->prog->aux->used_maps, env->used_maps,
...@@ -4339,9 +4338,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) ...@@ -4339,9 +4338,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
convert_pseudo_ld_imm64(env); convert_pseudo_ld_imm64(env);
} }
free_log_buf: err_release_maps:
if (log->level)
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.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册